I'm creating a small app in Rails 3.2.13, using bootstrap-sass gem.
I have the following situation:
My 'sign_up' controller has and 'index' action that creates a user like this:
#sign_up controller
def index
#user = User.new
end
Now, in my index.html.erb i have the form:
# sign_up controller => index.html.erb
<%= form_for #user, :html => {:class => 'form-horizontal'} do |f| %>
<div class = 'control-group'>
<%= f.label :username, :html => {:class => 'control-label'} %>
<%= text_field_tag :username, nil, :placeholder => 'Username' %>
</div>
<div class = 'control-group'>
<%= f.label :email, :html => {:class => 'control-label'} %>
<%= email_field_tag :email, nil, :placeholder => 'Email' %>
</div>
<div class = 'control-group'>
<%= f.label :password, :html => {:class => 'control-label'} %>
<%= password_field_tag :password, nil, :placeholder => 'Password' %>
</div>
<div class = 'control-group'>
<%= f.label :confirm_password, :html => {:class => 'control-label'} %>
<%= password_field_tag :confirm_password, nil, :placeholder => 'Confirm' %>
</div>
<%= f.submit 'Create', :class => 'btn btn-primary'%>
This will POST to users_controller, calling the create action:
# users controller
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
The problem is: the #user is saved, but the parameters are lost!
In the console log:
Started POST "/users" for 127.0.0.1 at 2013-05-29 12:14:47 -0300
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"wI5sNQV/lkn8GtYv5YkRLZ6HzxPg5MtoVXuarLulv30=", "username"=>"nonickname", "email"=>"no#bar.com", "password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "commit"=>"Create"}
(0.1ms) begin transaction
SQL (0.9ms) INSERT INTO "users" ("admin", "created_at", "email", "password_hash", "password_salt", "updated_at", "username") VALUES (?, ?, ?, ?, ?, ?, ?) [["admin", nil], ["created_at", Wed, 29 May 2013 15:14:47 UTC +00:00], ["email", nil], ["password_hash", nil], ["password_salt", nil], ["updated_at", Wed, 29 May 2013 15:14:47 UTC +00:00], ["username", nil]]
(148.9ms) commit transaction...
Why that happens, and how can i fix this? I know the form should be a users_controller domain(i plan to fix that), but it doesn't seem to be the problem!
Thanks for any help!
I'll try to help you here as much as I can. Have a look at the console when I create a comment:
Started POST "/companies/1/comments" for 127.0.0.1 at 2013-05-29 20:06:02 +0300
Processing by CommentsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"+J+ewToARuBybidK79V/3cFdX6=", "comment"=>{"content"=>"Lorem ipsum..."}, "commit"=>"Add Comments", "company_id"=>"1"}
(0.1ms) BEGIN
SQL (0.2ms) INSERT INTO `comments` (`commentable_id`, `commentable_type`, `content`, `created_at`, `updated_at`, `user_id`) VALUES (1, 'Company', 'Lorem ipsum...', '2013-05-29 17:06:02', '2013-05-29 17:06:02', 2)
(42.7ms) COMMIT
now when I say on conrtoller #comment = Comment.new(params[:comment]) means it will look for this line "comment"=>{"content"=>"Lorem ipsum dolor sit amet, ..."}
that means params[:comment] in my case is content, parameters are being sent as a hash and in your case you must have something like:
"user"=>{authenticity_token"=>"wI5sNQV/lkn8GtYv5YkRLZ6Hzx=", "username"=>"nonickname", "email"=>"no#bar.com", "password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]"}`
in your console logs. I've looked a few times in your console logs and didn't see the user there and you can't call #user = User.new(params[:user]) as long as it is missing.
about the form, if you are using:
<%= form_for #user, :html => {:class => 'form-horizontal'} do |f| %>
you could use f to build your fields and write less this way
<%= form_for #user, :html => {:class => 'form-horizontal'} do |f| %>
<div class = 'control-group'>
<%= f.label :username, :html => {:class => 'control-label'} %>
<%= f.text_field :username, :placeholder => 'Username' %>
</div>
<div class = 'control-group'>
<%= f.label :email, :html => {:class => 'control-label'} %>
<%= f.email_field :email, :placeholder => 'Email' %>
</div>
<div class = 'control-group'>
<%= f.label :password, :html => {:class => 'control-label'} %>
<%= f.password_field :passwor, :placeholder => 'Password' %>
</div>
<div class = 'control-group'>
<%= f.label :confirm_password, :html => {:class => 'control-label'} %>
<%= f.password_field :confirm_password, :placeholder => 'Confirm' %>
</div>
<%= f.submit 'Create', :class => 'btn btn-primary'%>
Ok, it's solved!
The problem was the bootstrap form, i need to set the name attribute:
...
<div class = 'control-group'>
<%= f.label :email, :html => {:class => 'control-label'} %>
<%= email_field_tag :email, nil, :name => 'user[email]', :placeholder => 'Email' %>
</div>
...
Thanks!
Related
I'm trying to build a nested form in a custom page using devise.
The error that comes out is: undefined method `build_profile' for nil:NilClass
<%= form_for("user", :url => user_registration_path) do |f| %>
<%= f.email_field :email, :autofocus => true, :placeholder => 'E-mail Address' %>
<%= f.password_field :password, :placeholder => 'Password' %>
<%= f.password_field :password_confirmation, :placeholder => 'Password Confirmation' %>
<% #user.build_profile %>
<%= f.fields_for :profile do |profile_form| %>
<%= profile_form.text_field :name, :placeholder => 'Name' %>
<%= profile_form.text_field :address, :placeholder => 'Address' %>
<%= profile_form.phone_field :phone, :placeholder => 'Phone (example: 0193284647)' %>
<% end %>
<p><%= f.submit "Sign up", :class=>'btn btn-primary' %> </p>
<% end %>
Edit (Extra information):
should i add #user = #user.build_profile by creating a users_controller.rb instead?
Would it cause problems with devise?
yes you have to do
#user = #user.build_profile
in registrations_controller.rb . And,mention the customize controller in routes.rb in devise method.
You should so something like
class Registrations < Devise::RegistrationsController
def new
#user = User.new
#user = #user.build_profile
super
end
end
I have the following model relationships:
OrderModel:
has_one :credit_card
accepts_nested_attributes_for :credit_card
attr_accessible :user_id, :date_updated, :date_finished, :amount, :payment_method, :status, :billing_cycle, :auth_net_subscription_id, :billing_start_date, :credit_card_attributes, :billing_address_id, :cc_id
CreditCardModel:
belongs_to :order
Here is my Order Controller (orders#checkout)
def checkout
#order = current_order
#cc = CreditCard.new
#order.build_credit_card
respond_with #order
end
Here is the form for entering in a CC on the order:
<%= form_for(#order, :url => finish_checkout_path, :html => { :class => 'validate' }) do |f| %>
<%= f.fields_for #cc do |cc| %>
<%= cc.text_field :cc_number, :placeholder => "Credit Card Number", :class => "full-width validate[required, creditCard] cc" %>
<%= cc.text_field :name, :placeholder => "Name as it appears on card", :class => "full-width validate[required]" %>
<%= select_month(Date.today, {:field_name => 'exp_month', :prefix => "order[credit_card]", :prompt => "EXP. MONTH"}, { :class => "dk half-width validate[required,past] marginRight10" }) %>
<%= select_year(Date.today, {:field_name => 'exp_year', :prefix => "order[credit_card]", :prompt => "EXP. YEAR", :start_year => Date.today.year, :end_year => Date.today.year + 10}, { :class => "dk half-width validate[required]" }) %>
<%= link_to "What's this?", "#", :class => 'cvv-help' %>
<%= cc.text_field :cvv, :class => 'half-width validate[required] marginRight10', :placeholder => "CVV" %>
<%= cc.text_field :zip_code, :class => 'half-width validate[required]', :placeholder => "Zip Code" %>
<% end %>
<%= f.hidden_field :amount, :value => #order.products.collect(&:price).reduce(&:+) %>
<p class="tos">By clicking the button below you agree to our terms of service.</p>
<p class="align-center"><%= f.submit "Submit", :class => 'btn submit' %></p>
<% end %>
And here is where I update the order (orders#finish):
current_order.update_attributes(params[:order])
When I do this, I get the following error: Can't mass-assign protected attributes: credit_card
I clearly have the credit_card_attributes in my attr_accessibleso I am not sure why this is erroring out.
Not sure, but it might be because of your controller code:
def checkout
#order = current_order
#cc = CreditCard.new
#order.build_credit_card
respond_with #order
end
With this, the credit card that you use in your fields_for is not linked to your order. That might be the problem.
Try doing that:
def checkout
#order = current_order
#order.build_credit_card
respond_with #order
end
and
<%= f.fields_for :credit_card do |cc| %>
I'm using devise for my user registrations and I'd like to have a separate edit path for user's to change/update their passwords. I've pulled the devise registrations views out and created a separate registrations controller like described in Railscast 236
I've tried creating a new action called change_password in the registrations controller but when I try to set the route with match '/change_password', to => 'registrations#change_password' I get an AbstractController::Actions Not Found
registrations controller
class RegistrationsController < Devise::RegistrationsController
def create
super
session[:omniauth] = nil unless #user.new_record?
end
def destroy
resource.destroy
set_flash_message :notice, :destroyed
sign_out_and_redirect(self.resource)
end
def change_password
render_with_scope :edit
end
private
def build_resource(*args)
super
if session[:omniauth]
#user.apply_omniauth(session[:omniauth])
#user.valid?
end
end
routes.rb
match 'auth/:provider/callback' => 'authentications#create'
resources :authentications
devise_for :users, :controllers => {:registrations => 'registrations'}
resources :posts do
member do
get :likers
end
collection do
get :search
end
end
resources :relationships, :only => [:create, :destroy]
resources :appreciations, :only => [:create, :destroy]
root :to => "pages#home"
match '/contact', :to => 'pages#contact'
match '/about', :to => 'pages#about'
match '/help', :to => 'pages#help'
match '/blog', :to => 'pages#blog'
resources :users do
member do
get :following, :followers, :likes
end
resources :collections
end
end
views/registrations/change_password.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :validate => true,
:html => { :method => :put }, :html => {:multipart => true}) do |f| %>
<%= devise_error_messages! %>
<p><strong>To change password, otherwise leave blank.</strong></p>
<p><%= f.label :current_password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :current_password %></p>
<p><%= f.label :password, "New password" %> <br />
<%= f.password_field :password %></p>
<p><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></p>
</div><br />
<p><%= f.submit "Update" %></p>
<% end %>
Try to pass match .. in the block of devise_for helper:
devise_for :users, :controllers => {:registrations => 'registrations'} do
match '/change_password', to => 'registrations#change_password'
end
I found this to be the easiest way to split the user edit form into edit & account
Originally I had
:name,
:email,
:avatar,
:location,
:website,
:bio,
:password (all in one form)
ROUTES (this provides route:
account_user GET /users/:id/account(.:format) users#account)
resources :users do
member do
get :following, :followers, :account
end
end
USERS_CONTROLLER.RB
before_filter :signed_in_user, only: [:index, :edit, :update, :destroy, :following, :followers, :account]
before_filter :correct_user, only: [:edit, :update, :account]
def edit
#user = User.find(params[:id])
end
def account
#title = "Account"
#user = User.find(params[:id])
end
def update
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
elsif #title = "Account"
render 'account'
else
render 'edit'
end
end
(split form views)
EDIT.HTML.ERB
<%= form_for #user, :html => { :multipart => true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :avatar %><br />
<%= f.file_field :avatar %>
<%= f.label :location %>
<%= f.text_field :location %>
<%= f.label :website %>
<%= f.text_field :website %>
<%= f.label :bio %>
<%= f.text_area :bio, placeholder: "About yourself in 160 characters or less..." %>
<%= f.submit "Update Profile", class: "btn btn-medium btn-primary" %>
<% end %>
ACCOUNT.HTML.ERB
<%= form_for #user, :html => { :multipart => true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Update Account", class: "btn btn-medium btn-primary" %>
<% end %>
SIDE NAV BAR INSIDE OF EDIT AND ACCOUNT VIEWS, SO THE USER HAS ACCESS TO EDIT AND ACCOUNT FORM
<ol class="nav nav-tabs nav-stacked">
<% #user ||= current_user %>
<li>
<a href="<%= edit_user_path(#user) %>">
Profile
<i class="icon-chevron-right"></i>
</a>
</li>
<li>
<a href="<%= account_user_path(#user) %>">
Account
<i class="icon-chevron-right"></i>
</a>
</li>
</ol>
Basically whats happening is I can create a new item that gets saved to my table in my db. but when I go to edit the item, the form opens up, I make the change and then when I go to submit, it takes me to the same url as the edit page and gives me Routing Error No route matches "/support/14/edit" although if you enter that in the address bar it opens the edit form just fine, but doesn't have any of my changes saved. So here is my code.
routes.rb
resources :support
support_controller.rb
def new
#support_item = Support.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #support_item }
end
end
# GET /support/1/edit
def edit
#support_item = Support.find(params[:id])
end
# POST /support
# POST /support.xml
def create
#support_item = Support.new(params[:support_item])
respond_to do |format|
if #support_item.save
format.html { redirect_to("/support", :notice => 'Question was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
# PUT /support/1
# PUT /support/1.xml
def update
#support_item = Support.find(params[:id])
respond_to do |format|
if #support_item.update_attributes(params[:support_item])
format.html { redirect_to("/", :notice => 'Question was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #support_item.errors, :status => :unprocessable_entity }
end
end
end
support.rb
class Support < ActiveRecord::Base
belongs_to :role
scope :admin_available, order("role_id ASC") do
Support.all
end
def self.available(user)
questions = where(:role_id => 1)
questions += where(:role_id => user.roles)
questions
end
end
_form.html.erb
<% if #support_item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#support_item.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #support_item.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label "Support item for:" %><br />
<%= f.collection_select :role_id, Role.find_by_max(5), :id, :name, {:default => 'everyone'} %>
</div>
<div class="field">
<%= f.label :question %><br />
<%= f.text_field :question, :class => 'genForm_question'%>
</div>
<div class="field">
<%= f.label :answer %><br />
<%= f.text_area :answer, :class => 'genForm_textarea' %>
</div>
<div class="field">
<%= f.label :url %><br />
<%= f.text_field :url, :class => 'genForm_question' %>
</div>
<div class="actions">
<%= f.submit %>
</div>
new.html.erb
<h1>New Support Item</h1>
<% form_for #support_item, :url => { :action => "create" }, :html => { :method => :post } do |f| %>
<%= render 'form', :f => f %>
<% end %>
edit.html.erb
<h1>Editing Support Item</h1>
<% form_for #support_item, :url => { :action => "edit" }, :html => { :method => :post } do |f| %>
<%= render 'form', :f => f %>
<% end %>
I believe thats all the relavent code.
<h1>Editing Support Item</h1>
<% form_for #support_item do |f| %>
<%= render 'form', :f => f %>
<% end %>
You are overriding the URL. It should be able to be auto-generated like that if you are doing everything with standard rest. If that doesn't work out, just know you don't want to submit to /support_items/1/edit, you want to submit to /support_items/1.
Can anyone please convert these haml code snippets to the equivalent html.erb?
1.
%h1
Edit Project Form
.edit_project
= semantic_form_for [:admin, #project], :url => admin_organization_project_path(#organization), :html => { :multipart => true } do |f|
= f.inputs do
= f.input :name
= f.input :status, :as => :select, :collection => Project.statuses
= f.input :overview
= f.input :funds_purpose
= f.input :goal
.files
= render :partial => 'admin/edit_photo', :collection => #project.project_photos, :locals => { :field_name => 'project[project_photos_attributes][][file]' }
= f.submit 'Save Project'
2.
%li.file.optional#project_project_photo_file_input
= label_tag 'File'
= image_tag edit_photo.file.url(:thumb) if edit_photo.file?
= file_field_tag field_name
For the second:
<li class="file optional" id="project_project_photo_file_input">
<%= label_tag 'File' %>
<%= image_tag edit_photo.file.url(:thumb) if edit_photo.file? %>
<%= file_field_tag field_name %>
</li>
for first:
<h1> Edit Project Form </h1>
<div class='edit_project'>
<%= semantic_form_for [:admin, #project], :url => admin_organization_project_path(#organization), :html => { :multipart => true } do |f| %>
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :status, :as => :select, :collection => Project.statuses%>
<%= f.input :overview %>
<%= f.input :funds_purpose %>
<%= f.input :goal %>
<div class='files' >
<%= render :partial => 'admin/edit_photo', :collection => #project.project_photos, :locals => { :field_name => 'project[project_photos_attributes][][file]' } %>
</div>
<% end %>
<%= f.submit 'Save Project' %>
<% end %>
</div>