Updating User password & email in separate forms but in same view - forms

My goal is to create a profile page where the (logged in) user can choose to either update their email or their password (in separate forms so not both at the same time) without navigating away from the page.
Updating one's email is as simple as entering their new email and hitting the "Save Changes" submit button.
Updating one's password requires the user to enter their old password, their new password, and a confirmation of their new password then hitting the "Update Password" button. The problem must be in the update_pwd method.
users_controller.rb
# ...
def edit # template: edit.html.erb
#user = User.find(current_user)
end
def update_email
#user = User.find(current_user)
if params[:commit] == 'Save Changes'
if #user.update_attributes(user_params_email)
redirect_to me_url
flash[:notice] = "Your changes have been saved"
else # either invalid or taken
render :edit
end
else
render :edit
end
end
def update_pwd
#user = User.find(current_user)
if params[:commit] == 'Update Password'
if #user.update_attributes(user_params_pwd) && User.find_by(username: current_user.username).try(:authenticate, params[:current_password])
redirect_to me_url
flash[:notice] = "Password updated!"
else
flash.now[:alert] = #user.errors.full_messages[0]
render :edit
end
else
render :edit
end
end
private
#def user_params
#params.require(:user).permit(:id, :username, :email, :password, :password_confirmation)
#end
def user_params_email
params.require(:user).permit(:email)
end
def user_params_pwd
params.require(:user).permit(:password, :password_confirmation, :current_password)
end
edit.html.erb
<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_email'}) do |f| %>
<% if #user.errors.any? %>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
<% end %>
<p> Current Email: <%= current_user.email %> </p>
<p> New Email: <%= f.text_field :email %> </p>
<%= f.submit "Save Changes" %>
<% end %>
<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_pwd'}) do |g| %>
<p>Old Password<br>
<%= password_field_tag :current_password, params[:password] %></p>
<p>New Password<br>
<%= g.password_field :password %></p>
<p>Confirm New Password<br>
<%= g.password_field :password_confirmation %></p>
<%= g.submit "Update Password" %>
<% end %>
routes.rb
# ...
get '/me' => 'users#edit'
patch '/me' => 'users#update_email'
patch '/me' => 'users#update_pwd'
# ...
Now, I've been able to get the email updating to work as desired (with the necessary error messages/validations and so forth) but whenever the update password button is clicked, the view is rendered but nothing happens. Instead, it seems as if the update_email function is being called:
Started PATCH "/me" for ::1 at 2015-05-20 10:34:31 -0500
Processing by UsersController#update_email as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"msEsj6yxfdrbXjjdm6cH3JamrFU8R1EoZ5asmE831GSxLwpiiIW/wmGrr9HiQxFDySJtW5MKK6Ezq9hZaMNFtA==", "current_password"=>"[FILTERED]", "user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Update Password"}
←[1m←[36mUser Load (0.0ms)←[0m ←[1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1←[0m [["id", 2]]
DEPRECATION WARNING: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`. (called from update_email ...)
user.rb
# ...
has_secure_password
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }
validates_uniqueness_of :email
validates :password, length:{ minimum: 8 }, on: :create
validates :password_confirmation, presence: true, on: :create
# ...
application_controller.rb
# ...
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
rescue ActiveRecord::RecordNotFound
end
Error log (as seen above)
Started PATCH "/me" for ::1 at 2015-05-20 10:34:31 -0500
Processing by UsersController#update_email as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"msEsj6yxfdrbXjjdm6cH3JamrFU8R1EoZ5asmE831GSxLwpiiIW/wmGrr9HiQxFDySJtW5MKK6Ezq9hZaMNFtA==", "current_password"=>"[FILTERED]", "user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Update Password"}
←[1m←[36mUser Load (0.0ms)←[0m ←[1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1←[0m [["id", 2]]
DEPRECATION WARNING: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`. (called from update_email ...)

You can try the following, I think this will help.
Please revert back if you face any issue.
routes.rb
get '/me' => 'users#edit'
patch '/me' => 'users#update_data'
edit.html.erb
<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_data'}) do |f| %>
<% if #user.errors.any? %>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
<% end %>
<p> Current Email: <%= current_user.email %> </p>
<p> New Email: <%= f.text_field :email %> </p>
<%= f.submit 'Save Changes', name: 'update_email' %>
<% end %>
<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_data'}) do |g| %>
<p>Old Password<br>
<%= password_field_tag :current_password, params[:password] %></p>
<p>New Password<br>
<%= g.password_field :password %></p>
<p>Confirm New Password<br>
<%= g.password_field :password_confirmation %></p>
<%= g.submit 'Update Password', name: 'update_password' %>
<% end %>
users_controller.rb
def edit
#user = User.find(current_user)
end
def update_data
#user = User.find(current_user)
if params[:commit] == "update_email"
if #user.update_attributes(user_params_email)
flash[:notice] = "Your changes have been saved"
redirect_to me_url
else
render :edit
end
elsif params[:commit] == "update_password"
if #user.update_attributes(user_params_pwd) && User.find_by(username: current_user.username).try(:authenticate, params[:current_password])
flash[:notice] = "Password updated!"
redirect_to me_url
else
flash.now[:alert] = #user.errors.full_messages[0]
render :edit
end
else
render :edit
end
end
private
def user_params_email
params.require(:user).permit(:email)
end
def user_params_pwd
params.require(:user).permit(:password, :password_confirmation, :current_password)
end

Related

Rails 4.2 Creating Multiple New Records with One Form

I have three models: Lesson, Questions and Answers.
What I'm trying to do is on the show lesson view, display the questions and allow users to create answers for each answer. However, I'm not sure the best way to do this.
I tried this approach on my lesson#showview:
<% #questions.each do |question| %>
<%= question.content %><br /><br />
<%= simple_form_for :answers do |f| %>
<%= f.input :content %>
<%= f.hidden_field :question_id, :value => question.id %>
<%= f.button :submit %>
<% end %>
<% end %>
With this code, I receive the error param is missing or the value is empty: lesson
Answer has two fields: content, question_id.
My other concern is that I'd like to have this be user friendly, so if there are multiple questions, there should be multiple input boxes for the answers (one per each question) and one submit button (so multiple answers can be posted at one time).
I think that my approach my bad, but I'm not sure how else to do this, so any help would be greatly appreciated.
Here's what I have so far:
Models:
class Lesson < ActiveRecord::Base
has_many :questions, dependent: :destroy
has_many :answers, through: :questions
accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :answers, reject_if: :all_blank, allow_destroy: true
end
class Question < ActiveRecord::Base
belongs_to :lesson
has_many :answers, dependent: :destroy
end
class Answer < ActiveRecord::Base
belongs_to :question
end
Lessons Controller
class LessonsController < ApplicationController
def show
#questions = #lesson.questions
end
# PATCH/PUT /lessons/1
# PATCH/PUT /lessons/1.json
def update
respond_to do |format|
if #lesson.update(lesson_params)
format.html { redirect_to #lesson, notice: 'Lesson was successfully updated.' }
format.json { render :show, status: :ok, location: #lesson }
else
format.html { render :edit }
format.json { render json: #lesson.errors, status: :unprocessable_entity }
end
end
end
private
def lesson_params
params.require(:lesson).permit(:name,
answers_attributes: [:id, :content, :question_id]
)
end
end
routes.rb
resources :lessons
post '/lessons/:id', to: "lessons#update"
Add gem in Gemfile and run bundle install:-
gem "nested_form"
On lession show page:-
<%= nested_form_for #lession do |lession_form| %>
<%= #lession.content %>
<%= lession_form.fields_for :questions do |question_form| %>
<% #questions.each do |question| %>
<%= question.content %><br /><br />
<%= question_form.fields_for :answers do |answer_form| %>
<%= answer_form.text_field :content %>
<%= answer_form.link_to_remove "Remove this answer" %>
<% end %>
<%= question_form.link_to_add "Add more answer", :answers %>
<% end %>
<% end %>
<%= lession_form.submit 'Update' %>
<% end %>
I would have thought you are able to achieve without the use of a Gem.
You may need to specify inverse_of in your model. I have previously found this was required in nested attributes when dealing with forms.
class Question < ActiveRecord::Base
belongs_to :lesson
has_many :answers, dependent: :destroy, :inverse_of => :question
end
class Lesson < ActiveRecord::Base
has_many :questions, dependent: :destroy, :inverse_of => :lessons
has_many :answers, through: :questions
#etc.
end
In your lessons controller:
def show
#lesson = Question.find(params[:id])
#questions = #lesson.questions
x.times { #lesson.questions.answer.build }
end
In your views/lessons/show page:
<%= form_for #lesson do |lesson| %>
<%= #lesson.whatever_attribute %>
<%= lesson.fields_for :questions do |question| %>
<% #questions.each do |question| %>
<%= question.content %>
<% end %>
<div id="answers-div" class='form-group'>
<%= question_form.fields_for :answers do |answer| %>
<%= answer.text_field :content id:"answer-entry" %>
<% end %>
</div>
<% end %>
<% end %>
<%= lesson.submit 'Submit' %>
Below the form add some buttons to add further answers or remove:
<button class="btn btn-default" id="addNewAnswer">Add Another Answer Box</button><br>
<button class="btn btn-default" id="deleteNewAnswer">Delete Last Answer</button>
You can then add & remove answers on the fly with jQuery.
$(document).ready(function(){
$("#addNewAnswer").click(function() {
$("#answers-div").append(createNewInputElement($("#answers-div")));
});
});
function createNewInputElement(form) {
var newIndex = $("#answers-div").children('input#choice-entry').length;
var newInput = $("#answer-entry").clone().attr('name', generateNewInputName(newIndex));
newInput.val('');
return newInput;
};
function generateNewInputName(idx) {
return "question[answers_attributes][" + idx + "][content]"
};
$(document).ready(function(){
$("#deleteNewAnswer").click(function() {
if ($("#answers-div input").length > 1) {
$("#answers-div input:last-child").remove();
}
});
});
The use of a nested form is not an issue. You require a nested form to allow you to nest answers within your lessson.questions but you are only allowing the user to give input
If using Rails 4 (and the Strong params) you will also need to allow these with something along these lines (otherwise the params being passed will not be allowed through).
private (in your Lessons controller)
def lesson_params
params.require(:lesson).permit(:content, answer_attributes:[:content])
end
This may not be perfect but it's the start of some sort of solution to your question I would hope.
Try to testing this code, an email me again
in your lesson#show.html.erb
<% for question in #lesson.questions %>
<%= question.content %><br /><br />
<%= simple_form_for :answers do |f| %>
<%= f.input :content %>
<%= f.hidden_field :question_id, :value => question.id %>
<%= f.button :submit %>
<% end %>
<% end %>

Devise Registration not showing "some" nested form fields Rails 4

I've got a modified Devise "sign_up" form (new registration) that includes fields for child and grandchild objects to be created along with the user. All of the model relationships are set up properly with access to the child's attributes. However, when the form renders, only the fields for the Devise user and one of the grandchildren is shown.
When a User is created, he/she will automatically be assigned a Customer object, an Account object, and an Address object. As you can see by the relationships in the User model below, User has one Customer and Customer has many Accounts and one Address. There was previously an issue with rendering the form at all, which I solved by changing the values passed to the builder method. WHY WON'T THIS WORK??? This is what I have so far:
*user.rb
class User < ActiveRecord::Base
before_create :generate_id
# Virtual attribute for authenticating by either username or email
# This is in addition to a real persisted field like 'username'
attr_accessor :login
has_one :customer, :dependent => :destroy
has_many :accounts, through: :customer
accepts_nested_attributes_for :customer, :allow_destroy => true
accepts_nested_attributes_for :accounts, :allow_destroy => true
has_one :address, through: :customer
accepts_nested_attributes_for :customer, :allow_destroy => true
accepts_nested_attributes_for :address, :allow_destroy => true
has_one :administrator
validates_uniqueness_of :email, :case_sensitive => false
validates_uniqueness_of :id
validates :username,
:presence => true,
:uniqueness=> {
:case_sensitive => false
}
# User ID is a generated uuid
include ActiveUUID::UUID
natural_key :user_id, :remember_created_at
belongs_to :user
# specify custom UUID namespace for the natural key
uuid_namespace "1dd74dd0-d116-11e0-99c7-5ac5d975667e"
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :timeoutable, :recoverable, :trackable, :validatable
# Generate a random uuid for new user id creation
def generate_id
self.id = SecureRandom.uuid
end
# Allow signin by either email or username ("lower" function might have to be removed?)
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_h).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions.to_h).first
end
end
end
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
# GET /users/sign_up
def new
#user = User.new
build_resource({})
self.resource[:customer => Customer.new, :account => Account.new, :address => Address.new]
respond_with self.resource
end
def create
#user = User.new
# Override Devise default behavior and create a customer, account, and address as well
resource = build_resource(params[:sign_up])
if(resource.save)
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
render :action => "new"
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:username, :email, :password, :password_confirmation,
customer_attributes: [:title, :firstname, :lastname, :phone1, :phone2],
account_attributes: [:acct_type],
address_attributes: [:address1, :address2, :zip_code])
}
end
end
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
def after_sign_in_path_for(resource)
if current_user.role == 'admin'
adminview_administrator_path(current_user, format: :html)
else
accounts_path(current_user, format: :html)
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation,
customer_attributes: [:title, :firstname, :lastname, :phone1, :phone2],
account_attributes: [:acct_type],
address_attributes: [:address1, :address2, :zip_code]) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :username, :email, :password) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password) }
end
end
views/devise/registrations/new.html.erb
<h1>Create an account</h1>
<div class="panel panel-default" style="width: 50%; padding: 0 25px;">
<%= bootstrap_nested_form_for(resource, as: resource_name, url: user_registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<h3>User Info</h3>
<!-- fields for User object -->
<%= f.text_field :username, autofocus: true %>
<%= f.email_field :email %>
<%= f.password_field :password , autocomplete: "off"%>
<% if #validatable %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
<!-- fields for Customer object -->
<%= f.fields_for :customer do |customer_fields| %>
<%= customer_fields.text_field :title %>
<%= customer_fields.text_field :firstname %>
<%= customer_fields.text_field :lastname %>
<%= customer_fields.text_field :phone1 %>
<%= customer_fields.text_field :phone2 %>
<% end %>
<!-- fields for Account object -->
<%= f.fields_for :account do |account_fields| %>
<%= account_fields.text_field :acct_type %>
<% end %>
<!-- fields for Address object -->
<%= f.fields_for :address do |address_fields| %>
<%= address_fields.text_field :address1 %>
<%= address_fields.text_field :address2 %>
<%= address_fields.text_field :zip_code %>
<% end %>
<br />
<div class="actions">
<%= f.submit "Create My Account", :class => "btn btn-info" %>
</div>
<% end %>
</div>
</div>
Again, the above view does render, but the form only displays the fields for Devise new user and the one field (acct_type) for the account fields. How to get the rest of form to display and create all of these things on submission? Everything I've tried and everything I've read leads me to think that there's a problem with Rails 4's strong_parameters not being able to recognize the permitted attributes (see above controllers) in an array. Could that be the issue? If so, how does one go about passing the parameters necessary to build all these things?
Could be problem with the routes?
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations" }
devise_scope :user do
# authentication
post "/accounts/adminview" => "devise/sessions#new"
end
root 'home#index'
resources :administrators do
member do
get :adminview
end
end
resources :users do
resource :customers
resource :accounts
resource :addresses
end
resources :account_types, :accounts, :addresses, :administrators, :customers, :transaction_types, :transactions, :users
end
I've tried every combination of ways that I could find on SO. This has taken up days worth of valuable time. I don't see any reason why it can't work. Does anyone have a better way of doing this? Is there a gem that would help? I'm willing to tear Devise apart and rebuild if necessary.
F.Y.I. It's Rails 4 and Devise 3.4.1. I've also added nested_form gem, but it doesn't make a difference.
Thank you
If you raise your params in controller you probably see accounts_attributes instead account_attributes you are setting in permit at application_controller, try replace it.

Ruby on Rails Tutorial (Book) Chapter 7 (3rd Edition) - No route matches [POST] "/signup"

I'm getting an 'No route matches [POST] "/signup"' error when in Chapter 7, I try to submit the signup form.
These are my routes:
root_path GET / static_pages#home
help_path GET /help(.:format) static_pages#help
about_path GET /about(.:format) static_pages#about
contact_path GET /contact(.:format) static_pages#contact
signup_path GET /signup(.:format) users#new
login_path GET /login(.:format) sessions#new
logout_path GET /logout(.:format) sessions#destroy
users_path GET /users(.:format) users#index
POST /users(.:format) users#create
new_user_path GET /users/new(.:format) users#new
edit_user_path GET /users/:id/edit(.:format) users#edit
user_path GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
sessions_path POST /sessions(.:format) sessions#create
new_session_path GET /sessions/new(.:format) sessions#new
session_path DELETE /sessions/:id(.:format) sessions#destroy
This is my Users controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to users_path(#user)
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
And this is the view where the signup gets posted from:
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for #user do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
Here is my routes file:
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
resources :users
resources :sessions, only: [:new, :create, :destroy]
end
Place your resources at the top of the routes.rb file, here is my routes.rb:
Rails.application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
root 'static_pages#home'
match '/signup' , to: 'users#new' , via: 'get'
match '/login' , to: 'sessions#new' , via: 'get'
match '/logout' , to: 'sessions#destroy' , via: 'delete'
match '/help' , to: 'static_pages#help' , via: 'get'
match '/about' , to: 'static_pages#about' , via: 'get'
match '/contact' , to: 'static_pages#contact', via: 'get'
end
Instead of:
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
resources :users
resources :sessions, only: [:new, :create, :destroy]
end
Chapter 7 doesn't have any references to sessions.
That happens in Chapter 8.
This is how the routes look like at the end of Chapter 7.
Rails.application.routes.draw do
root 'static_pages#home'
get 'about' => 'static_pages#about'
get 'help' => 'static_pages#help'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
resources :users
end

Form with nested models with many to many through relationship "can't assign mass attributes" error

I am stuck on the error "Can't mass-assign protected attributes: user" for my form. I have a user that creates a family and other users through a single form. Currently I am trying to create the functionality to have the user create a new family and one new user in one form. I have the Cocoon gem installed and am using Rails 3.2.16. https://github.com/nathanvda/cocoon
The error is occuring on this line
families_controller.rb
def create
binding.pry
#user = current_user
#family = Family.new(params[:family]) <<<<<
The params are:
=> {"utf8"=>"✓",
"authenticity_token"=>"EqWGxK3Fuj2uYk3namWK9SbXLPRKSn6cReT7wQddG0E=",
"family"=>
{"name"=>"test Family",
"users_attributes"=>{"0"=>{"first_name"=>"jane", "last_name"=>"smith"}}},
"commit"=>"Create Family",
"action"=>"create",
"controller"=>"families"}
Models
user.rb
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :age_months, :height_inches, :weight_ounces
has_many :user_families
has_many :families, through: :user_families
end
family.rb
class Family < ActiveRecord::Base
attr_accessible :location, :name, :users_attributes, user_families_attributes
has_many :user_families
has_many :users, through: :user_families
accepts_nested_attributes_for :users, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :user_families, :reject_if => :all_blank, :allow_destroy => true
end
View
families.new.html.erb
<%= form_for(#family) do |f| %>
<form class = 'form-horizontal' role = 'form'>
<div class='form-group'>
<%= f.label :name %>
<%= f.text_field :name, placeholder: 'Family Name' %>
</div>
<div class='form-group'>
<%= f.fields_for #new_user do |ff| %>
<%= label_tag :first_name %>
<%= ff.text_field :first_name, placeholder: 'First Name' %>
<%= label_tag :last_name %>
<%= ff.text_field :last_name, placeholder: 'Last Name' %>
<%= label_tag :age_months %>
<%= ff.number_field :age_months, placeholder: 'Enter Age' %>
<%= label_tag :height_inches %>
<%= ff.number_field :height_inches, placeholder: 'Height in Inches' %>
<%= label_tag :weight_ounces %>
<%= ff.number_field :weight_ounces, placeholder: 'Weight in Pounds' %>
<% end %>
</div>
<div class='actions'>
<%= f.submit %>
</div>
</form>
<% end %>
Controller
families_controller.rb
class FamiliesController < ApplicationController
def index
#families = Family.all
end
def show
#user = current_user
#family = Family.find(params[:id])
end
def new
#user = current_user
#family = Family.new(name: "#{#user.last_name} Family")
#family.users.build
#new_user = User.new
end
def edit
#family = Family.find(params[:id])
end
def create
#user = current_user
#family = Family.new(params[:family])
#family.users << #user
#family.save
redirect_to root_path
end
def update
#family = Family.find(params[:id])
#family.update_attributes(params[:family])
#family.save
redirect_to root_path(anchor: 'profile')
end
def destroy
#family = Family.find(params[:id])
#family.destroy
redirect_to families_path
end
end
Family and User are associated with 1-M relationship.
In your view families/new.html.erb
Change
<%= f.fields_for #new_user do |ff| %>
To
<%= f.fields_for :users, #new_user do |ff| %>

What is wrong with my coffeescript in Stripe?

I've been working on integrating Stripe into my web application, and it doesn't seem to be working. To help me along, I've been using Ryan Bates's Rails Cast on integrating Stripe. Whenever I try to run the payment form, I get an error saying that "There was a problem with my credit card". I think the problem lies in my coffeescript file, but perhaps I'm wrong. I've included the stripe user token as a part of my user model instead of placing it into its own subscription model. Here is the coffeescript code I have:
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
subscription.setupForm()
user =
setupForm: ->
$('#new_user').submit ->
$('input[type=submit]').attr('disabled', true)
if $('#card_number').length
user.processCard()
false
else
true
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
expMonth: $('#card_month').val()
expYear: $('#card_year').val()
Stripe.createToken(card, user.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 500
$('#user_stripe_card_token').val(response.id)
$('#new_user')[0].submit()
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)
I'm a beginner when it comes to programming, so any help you can give me would be great.
Here's the error I get in my terminal when I try to sign up:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Xas+iA+a3op7jUi57qTr7XWQSClPscA7fR19rkclkEE=", "user"=>{"stripe_card_token"=>"", "name"=>"Jack", "email"=>"email#example.com", "phone_number"=>"203-xxx-xxxx", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Create my account"}
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('jjets718#yahoo.com') LIMIT 1
Stripe error while creating customer: Invalid token id:
My view for the signup is this:
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.hidden_field :stripe_card_token %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :phone_number, "Your cell phone number" %>
<%= f.text_field :phone_number %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Password confirmation" %>
<%= f.password_field :password_confirmation %>
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil %>
<%= label_tag :card_code, "Security Code on Card (CVV)" %>
<%= text_field_tag :card_code, nil, name: nil %>
<%= label_tag :card_month, "Card Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"}%>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
My code for my controller is this for the create method:
def create
#user = User.new(params[:user])
if #user.save_with_payment
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to edit_user_path(current_user)
UserMailer.welcome_email(#user).deliver
else
render 'new'
end
end
My code for the database migration for the user token is this:
class AddStripeToUsers < ActiveRecord::Migration
def change
add_column :users, :stripe_customer_token, :string
end
end
And the code for the save_with_payment method in my model is this:
def save_with_payment
if valid?
customer = Stripe::Customer.create(description: email, plan: 1, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
2 things that come to mind:
You should be doing a status check for 200, not 500
You may need to require the coffeescript file in your application.js
e.g. //= require users
I could be wrong, but at this point:
handleStripeResponse: (status, response) ->
if status == 500
$('#user_stripe_card_token').val(response.id)
In addition to changing if status == 500 to if status == 200, this line $('#user_stripe_card_token').val(response.id) may need to be $('#new_user_stripe_card_token').val(response.id). Make sure to check the input ID.