I need a button such that when I click it, the name attribute must be be updated in user table and an address must be saved in address table. address table belongs to user table. Now my error is that when I click submit button i am not able to save the address but my name gets updated in the user table. Can anyone help with it?
Controller Code
class ProfileController < ApplicationController
before_action :set_user, only: %i[index update_profile]
def index; end
def create
#address = Address.new(address_params)
respond_to do |format|
puts'-=-==-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-='
if #address.save
format.html { redirect_to profile_index_path, notice: 'Address was successfully created.' }
else
format.html { render :new }
end
end
end
def update_profile
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to profile_index_path, notice: 'Profile was successfully updated.' }
else
format.html { render :index }
end
end
end
private
def set_user
#user = User.find(current_user.id)
#user.address || #user.build_address
end
def user_params
params.require(:user).permit(:name, address_attributes: %i[area state country])
end
def address_params
params.require(:address).permit(address: %i[area state country])
end
end
Model
address.rb
class Address < ApplicationRecord
belongs_to :user
end
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :address, dependent: :destroy
validates :name, presence: true
def admin?
true
end
end
View Code
<%= form_for(#user, url: { action: 'update_profile' }, html: { class: 'm-form m-form--fit m-form--label-align-right' } ) do |f| %>
<% if #user.errors.any? %>
<h4><%= pluralize(#user.errors.count, "error") %>
prohibited this profile from being saved:</h4>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<div class="form-group m-form__group row">
<label for="name" class="col-2 col-form-label">
Name
</label>
<div class="col-7">
<%= f.text_field :name, class: 'form-control m-input', placeholder: 'Full Name' %>
</div>
</div>
<div class="m-form__seperator m-form__seperator--dashed m-form__seperator--space-2x"></div>
<%= f.fields_for #user.address do |a| %>
<div class="form-group m-form__group row">
<label for="example-text-input" class="col-2 col-form-label">
Address
</label>
<div class="col-7">
<%= a.text_field :area, class: 'form-control m-input', placeholder: 'Address' %>
</div>
</div>
<div class="form-group m-form__group row">
<label for="example-text-input" class="col-2 col-form-label">
City
</label>
<div class="col-7">
<%= a.text_field :city, class: 'form-control m-input', placeholder: 'City' %>
</div>
</div>
<div class="form-group m-form__group row">
<label for="example-text-input" class="col-2 col-form-label">
State
</label>
<div class="col-7">
<%= a.text_field :state, class: 'form-control m-input', placeholder: 'State' %>
</div>
</div>
<% end %>
<%= f.submit 'Save Changes', class: 'btn btn-accent m-btn m-btn--air m-btn--custom' %>
<%= link_to 'Back', root_path, class: 'btn btn-secondary m-btn m-btn--air m-btn--custom' %>
routes.rb
resources :profile do
collection do
patch 'update_profile'
get 'update_profile'
end
end
Terminal log
Started PATCH "/profile/update_profile" for 127.0.0.1 at 2018-05-07 12:33:15 +0530
Processing by ProfileController#update_profile as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"AJZaELC5GwhOsBCKRZMQMpKySMxNpIIHgNpFBuS1KbBFSs61ByG7RAxVXV8Rd7QXaQ7Htzgyty4Z1uclocXOhQ==", "user"=>{"name"=>"Karthi", "email"=>"suriya#gmail.com", "address"=>{"area"=>"L1, 54th St. & 9th Ave. Ashok Nagar", "city"=>"Chennai", "state"=>"Tamil Nadu", "country"=>"India", "postcode"=>"600083"}}, "commit"=>"Save Changes"}
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1
Address Load (0.3ms) SELECT `addresses`.* FROM `addresses` WHERE `addresses`.`user_id` = 7 LIMIT 1
Unpermitted parameter: :address
(0.1ms) BEGIN
(0.2ms) COMMIT
Redirected to http://localhost:3000/profile
Completed 302 Found in 7ms (ActiveRecord: 1.2ms)
Started GET "/profile" for 127.0.0.1 at 2018-05-07 12:33:15 +0530
Processing by ProfileController#index as HTML
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1
Address Load (0.2ms) SELECT `addresses`.* FROM `addresses` WHERE `addresses`.`user_id` = 7 LIMIT 1
Rendering profile/index.html.erb within layouts/application
Rendered profile/_profile_card.html.erb (0.3ms)
Rendered profile/_profile_detail.html.erb (1.7ms)
Rendered profile/index.html.erb within layouts/application (3.4ms)
Rendered layouts/_web_font.html.erb (0.3ms)
Rendered layouts/_google_analytics.html.erb (0.2ms)
Rendered layouts/_header.html.erb (1.8ms)
Rendered layouts/_alerts.html.erb (0.4ms)
Completed 200 OK in 32ms (Views: 28.7ms | ActiveRecord: 0.7ms)
I have omitted a few methods unrelated to the error and made some changes to the controller:
class ProfileController < ApplicationController
def create
#address = Address.new(address_params)
respond_to do |format|
if #address.save
format.html { redirect_to profile_index_path, notice: 'Address was successfully created.' }
else
format.html { render :new }
end
end
end
def update_profile
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to profile_index_path, notice: 'Profile was successfully updated.' }
else
format.html { render :index }
end
end
end
private
def user_params
# changed `address_attributes` to `address` as the params in request contains key `address`
params.require(:user).permit(:name, address: %i[area state country])
end
def address_params
# permit the attributes directly instead of nesting them under another `address` key
params.require(:address).permit(*%i[area state country])
end
end
Let me know if it doesn't work.
Please add below line in your user model
user.rb
accepts_nested_attributes_for :address
Related
I have a form that has a few fields that should populate to my database which it doesn't. I am unsure why this is. I defined the parameters which fixed another error but my data is not being stored. My table name is users.
My controller:
Class LandlordPageController < ApplicationController
before_action :get_user
def get_user
#user = current_User
end
def index
end
def show
end
def create
#user = User.new(user_params)
#user.save
redirect_to profile_page_index_path
end
private
def user_params
params.require(:user).permit(:address, :cityResiding, :ssn, :birthDate, :gender, :phoneNumber)
end
end
My form:
<%= form_for :user do |f| %>
<div class="field">
<%=f.label :address, 'Current Address' %><br/>
<%= f.text_field :address, :required => 'required' %>
</div>
<div class="field">
<%=f.label :cityResiding, 'Current City' %><br/>
<%= f.text_field :cityResiding, :required => 'required' %>
</div>
<div class="field">
<%=f.label :phoneNumber, 'Phone Number'%><br/>
<%= f.telephone_field :phoneNumber, maxlength: 15, :required => 'required' %>
</div>
<div class="field">
<%=f.label :gender, 'Gender'%><br/>
<%= f.select :gender, ['',' Male', 'Female', 'Other','Prefer Not to Answer']%>
</div>
<div class="field">
<%=f.label :birthDate, 'Birth Date'%><br/>
<%= f.date_select :birthDate, order: [:month, :day, :year], :required => 'required'%>
</div>
<div class="field">
<%=f.label :ssn, 'Social Security Number' %><br/>
<%= f.text_field :ssn, maxlength: 9 %>
</div>
<div class="actions">
<%= f.submit "Submit Information" %>
</div>
<% end %>
log:
Started GET "/landlord_page" for 127.0.0.1 at 2016-11-06 17:59:58 -0500
Processing by LandlordPageController#index as HTML
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering landlord_page/index.html.erb within layouts/application
Rendered landlord_page/index.html.erb within layouts/application (4.0ms)
Rendered layouts/_navbar.html.erb (1.0ms)
Completed 200 OK in 98ms (Views: 88.4ms | ActiveRecord: 0.0ms)
Started POST "/landlord_page" for 127.0.0.1 at 2016-11-06 18:00:06 -0500
Processing by LandlordPageController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"98tUidqprFyTG8ZC/tV9TRDIVlV0I+ocnQfKTUDqorlS+JMFHtaCWz69EwBvH5MrHhnRbg93m695//Z1I5xt3A==", "user"=>{"address"=>"1", "cityResiding"=>"1", "phoneNumber"=>"1", "gender"=>" Male", "birthDate(2i)"=>"11", "birthDate(3i)"=>"6", "birthDate(1i)"=>"2016", "ssn"=>""}, "commit"=>"Submit Information"}
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.0ms) begin transaction
(0.0ms) rollback transaction
Redirected to http://localhost:3000/profile_page
Completed 302 Found in 4ms (ActiveRecord: 0.0ms)
EDIT: My form does submit data but this error is being thrown on save
NoMethodError in LandlordPageController#create
undefined method `save' for #<Array:0x0000000d883a08>
Instead of new I went with update and removed the save, because the new already executed saving the parameters and save was trying to save nil parameters. I was not creating a new user but meaning to add new parameters to an existing user. This is why the error occured. The full final code is below.
def create
respond_to do |format|
if User.update(user_params)
format.html { redirect_to profile_page_index_path, notice: 'Landlord application successfully submitted.' }
format.json { render :show, status: :created, location: #user }
else
format.html { redirect_to profile_page_index_path, notice: 'Landlord application was not successfully submitted.' }
format.json { render :show, status: :unprocessable_entity }
end
end
end
As has been said, the issue is probably validation errors.
If you mean to update the user, you will need to use the update method instead and pass the user to the form
form_for #user
That will send a PATCH request to the update method on the controller once the form is submitted.
def update
#user.update user_params
if ! #user.valid?
flash[:error] = #user.errors.full_messages
end
redirect_to profile_page_index_path
end
I am trying to nest a user to an account and allow the user to be created when the account is created. I am having an issue when creating both the account and user from the same form, and my server output is not very helpful in trying to isolate the problem.
here is the output when I try to save the Account and User.
Started POST "/accounts" for ::1 at 2016-10-10 20:55:23 -0600
Processing by AccountsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"UK7h4edNzRomi7JGomoZD1ayYmlNxI/h2ZH+NEaJxWQzcFsYAJujr5EDDS2HeprAX41IuS5/crRxmXYz80YpYw==", "account"=>{"subdomain"=>"mydomain", "owner_attributes"=>{"email"=>"swilson#ta#####td.com", "f_name"=>"S####", "l_name"=>"W####", "date_of_birth"=>"19##-##-##", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}, "commit"=>"Create Account"}
(0.3ms) BEGIN
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "swilson#ta#####td.com"], ["LIMIT", 1]]
Account Exists (0.3ms) SELECT 1 AS one FROM "accounts" WHERE "accounts"."subdomain" IS NULL LIMIT $1 [["LIMIT", 1]]
(0.2ms) ROLLBACK
Rendering accounts/new.html.erb within layouts/application
Rendered accounts/_form.html.erb (3.8ms)
Rendered accounts/new.html.erb within layouts/application (5.1ms)
Rendered shared/_signed_out_nav.html.erb (1.3ms)
Completed 200 OK in 183ms (Views: 44.2ms | ActiveRecord: 1.1ms)
I believe the issue may have something to do with the account generation and the subdomain. but I Can not pin it down for the life of me!
also I commented out my personal info with the ####...
here is my account controller
class AccountsController < ApplicationController
def new
#account = Account.new
#account.build_owner
end
def create
#account = Account.new(account_params)
respond_to do |format|
if #account.save
format.html {redirect_to root_path, notice: 'Account successfully created.'}
else
format.html {render :new, alert: 'There was a problem, please try again.'}
end
end
end
private
def account_params
params.require(:account).permit(:subdomain, owner_attributes: [:email, :password, :password_confirmation, :f_name, :l_name, :date_of_birth])
end
def set_account
#account = Account.find(params[:id])
end
end
here is my account form:
<%= bootstrap_form_for(#account) do |f| %>
<div class="row">
<div class="col-xs-12">
<%= f.text_field :subdomain, hide_label: true, placeholder: 'Company Name', append: ".patrolvault.net" %>
</div>
</div>
<%= f.fields_for :owner do |o| %>
<div class="row">
<div class="col-xs-12">
<%= o.email_field :email, label: 'Email Address' %>
</div>
<div class="col-xs-12">
<%= o.text_field :f_name, label: 'First Name' %>
</div>
<div class="col-xs-12">
<%= o.text_field :l_name, label: 'Last Name' %>
</div>
<div class="col-xs-12">
<%= o.date_field :date_of_birth, label: 'Date Of Birth' %>
</div>
<div class="col-xs-6">
<%= o.password_field :password, label: 'Password' %>
</div>
<div class="col-xs-6">
<%= o.password_field :password_confirmation, label: 'Confirm Password' %>
</div>
</div>
<% end %>
<%= f.submit :class => 'btn btn-primary' %>
<% end %>
and here is my account model:
class Account < ApplicationRecord
# Before Actions
before_validation :downcase_subdomain
# Relationships
belongs_to :owner, class_name: 'User', optional: true
accepts_nested_attributes_for :owner
# Validations
validates :owner, presence: true
RESTRICTED_SUBDOMAINS = %w(www, patrolvault, test)
validates :subdomain, presence: true,
uniqueness: { case_sensitive: false },
format: { with: /\A[\w\-]+\Z/i, message: 'Contains invalid characters.' },
exclusion: { in: RESTRICTED_SUBDOMAINS, message: 'Restricted domain name'}
# Custom Methods
private
def downcase_subdomain
self.subdomain = subdomain.try(:subdomain)
end
end
Please let me know if you require further info or if I have missed something! Thanks!
so the problem was in my before_validation :downcase_subdomain. once I removed that and the matching method everything began to work fine. I will rework this.
Thanks.
There are already a couple of questions addressing this issue:
render/redirect to new action when validation fails (rails)
Keeping validation errors after redirect from partial back to the same page that has the partial
I tried to implement some of the solutions recommended but did not manage fixing my issue.
So here we go.
In my Rails 4 app, there are four models:
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
has_many :invitations, :class_name => "Invite", :foreign_key => 'recipient_id'
has_many :sent_invites, :class_name => "Invite", :foreign_key => 'sender_id'
end
class Calendar < ActiveRecord::Base
has_many :administrations
has_many :users, through: :administrations
has_many :invites
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Invite < ActiveRecord::Base
belongs_to :calendar
belongs_to :sender, :class_name => 'User'
belongs_to :recipient, :class_name => 'User'
end
Here, we are going to focus on the Invite and the Calendar models.
In the calendar edit view, I have a form to create a new invite:
<h2>Edit <%= #calendar.name %> calendar</h2>
<%= render 'form' %>
<h2>Invite new users to <%= #calendar.name %> calendar</h2>
<%= form_for #invite , :url => invites_path do |f| %>
<%= f.hidden_field :calendar_id, :value => #invite.calendar_id %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label "Role" %>
<%= f.radio_button(:recipient_role, "Editor") %>
<%= f.label "Editor" %>
<%= f.radio_button(:recipient_role, "Viewer") %>
<%= f.label "Viewer" %>
<%= f.submit 'Send' %>
<% end %>
<%= link_to 'Show', calendar_path %> |
<%= link_to 'Back', calendars_path %>
–––––
UPDATE: please note that I have defined a calendars.html.erb layout for my calendar views, including the following code to display alerts:
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %>">
<%= value %>
</div>
<% end %>
–––––
In the Invite model, I want to validate the presence of :email and :recipient_role (both values submitted by the user through the form), so I added this to the Invite model:
validates :email, :recipient_role, presence: true
And I would like users to be redirected to the form with an error message if they forgot to fill one of these two fields, which I implemented with the following code in the InvitesController:
class InvitesController < ApplicationController
def create
# some code
if #invite.save
# some code
else
format.html { render :template => "calendars/edit", notice: 'Invitation could not be sent.' }
end
redirect_to calendar_path(#calendar), notice: 'Invitation was successfully sent.'
end
private
def invite_params
params.require(:invite).permit(:email, :calendar_id, :recipient_role)
end
end
In particular, I thought that the line format.html { render :template => "calendars/edit", notice: 'Invitation could not be sent.' } would allow me to do what I wanted, as recommended here.
However, when I try to submit the form with at least an empty field, I get the following error:
ArgumentError in InvitesController#create
too few arguments
end
else
format.html { render :template => "calendars/edit", notice: 'Invitation could not be sent.' }
end
redirect_to calendar_path(#calendar), notice: 'Invitation was successfully sent.'
end
And this is the server log:
Processing by InvitesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"p+yxM9Tw3JiNw/6Chv9//N8uvWhMy0TqrudTu0y9D9zXCl6kK2LtCqPu1rvTGv5gOMBuv2RK/IX2MBpWUTelZw==", "invite"=>{"calendar_id"=>"3", "email"=>"test#example.com"}, "commit"=>"Send"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Calendar Load (0.1ms) SELECT "calendars".* FROM "calendars" WHERE "calendars"."id" = ? LIMIT 1 [["id", 3]]
(0.0ms) begin transaction
(0.0ms) rollback transaction
Completed 500 Internal Server Error in 27ms (ActiveRecord: 1.3ms)
ArgumentError (too few arguments):
app/controllers/invites_controller.rb:16:in `format'
app/controllers/invites_controller.rb:16:in `create'
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1#global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/_source.erb (3.7ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1#global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.5ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1#global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.9ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1#global/gems/actionpack-4.2.2/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (54.0ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb (0.3ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.3ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.4ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.3ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb within layouts/javascript (36.5ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb within layouts/javascript (0.2ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.5ms)
Rendered /Users/TXC/.rvm/gems/ruby-2.2.1/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb (83.2ms)
What am I doing wrong?
Do the following things please
def create
# some code
if #invite.save
redirect_to calendar_path(#calendar), notice: 'Invitation was successfully sent.'
else
render template: "calendars/edit", notice: 'Invitation could not be sent.'
end
end
I have a Rails app that builds both a User and an Organization when the first User signs up (User belongs_to Organization). This works fine, and if you fail to put in e.g. the email address (or use an incorrect one) then the form renders the relevant rails error messages just fine. I have additional logic that ensures the first User to sign up an Organization becomes the Admin User of that Organization, and they are permitted to add other users to the site too. If you try and sign up with an existing Organization name it's not permitted.
My tests are all fine, and I'm using the skeleton logic for authentication and authorization provided by the Hartl tutorial (not the new draft one). What I recently noticed was that when an Admin User inputs a blank form for a new user, the app returns to the Organization page and displays a success message. No User object is built (so some part of the app is still working) - I just don't want this to happen (I want the error messages displayed). I can't quite work out what is happening here - why wouldn't the "validates" statements return the errors in this case? Anyway - here's my code:
User.rb:
class User < ActiveRecord::Base
belongs_to :organization
has_many :sales_opportunities
before_save { self.email = email.downcase }
before_destroy :allocate_sales_opportunities_to_admin
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }
validates :organization, presence: true
Organization.rb:
class Organization < ActiveRecord::Base
validates :organization_name, presence: true, length: { maximum: 50 }, uniqueness: true
has_many :users, :inverse_of => :organization, dependent: :destroy
has_many :companies, :inverse_of => :organization, dependent: :destroy
has_many :products, :inverse_of => :organization, dependent: :destroy
has_many :competitors, :inverse_of => :organization, dependent: :destroy
accepts_nested_attributes_for :users
after_create :set_admin
def users_for_form
collection = users.where(organization_id: id)
collection.any? ? collection : users.build
end
private
def set_admin
if self.users.count == 1
self.users.first.update_attribute(:admin, true)
else
return true
end
end
end
Users controller:
class UsersController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update]
before_action :correct_user, only: [:edit, :update, :show]
before_action :admin_user, only: :destroy
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def create
if signed_in?
#organization = Organization.find(params[:organization_id])
#organization.users.create(user_params)
flash[:success] = "You added a new user to your organization. Send them their login details today!"
redirect_to #organization
else
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Thanks for signing up with My App! This is your profile page, be sure to take a look at the support link in the footer"
redirect_to #user
else
render 'new'
end
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation, organization_attributes: [:organization_name, :organization_id])
end
#before filters
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in." unless signed_in?
end
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
def correct_user
#user = User.find(params[:id])
#organization = #user.organization
redirect_to root_url, notice: "You are not permitted to visit that page. Please create an account or sign in" unless current_user?(#user) || #user.organization == current_user.organization
end
end
Organization's controller:
class OrganizationsController < ApplicationController
before_action :signed_in_user, only: [:edit, :update, :show]
before_action :correct_org, only: [:edit, :update, :show]
def new
#organization = Organization.new
#organization.users.build
end
def create
#organization = Organization.new(organization_params)
if #organization.save
#user = #organization.users.first
sign_in #user
flash[:success] = "Thanks for signing up with My App! This is your profile page, be sure to take a look at the support link in the footer"
redirect_to #user
else
render 'new'
end
end
I'm sure I've got some ugly code in here (the Organizations and Users features were the first new functionality I built when learning RoR and deviating from the Hartl course), and I can't quite work out why the validations are working (no User object is created) when the error message handling is not. For completeness here's the add user form:
<% provide(:title, 'Add more users to your organization') %>
<div class-"container-fluid">
<h1>Sign up colleagues using the form below:</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="well">
<%= form_for([:organization, #user], :html => {:class => "form-horizontal"}) do |f| %>
<%= render 'shared/error_messages' %>
<div class="form-group">
<%= f.label :name, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= f.text_field :name, :placeholder => "What's their name?" %>
</div>
</div>
<div class="form-group">
<%= f.label :email, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= f.text_field :email, :placeholder => "Enter their email address" %>
</div>
</div>
<div class="form-group">
<%= f.label :password, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= f.password_field :password, :placeholder => "Provide a password" %>
</div>
</div>
<div class="form-group">
<%= f.label :password_confirmation, "Repeat Password", :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= f.password_field :password_confirmation, :placeholder => "Repeat password" %>
</div>
</div>
<%= f.submit "Add new user account", class: "btn btn-large btn-success" %>
<% end %>
</div>
</div>
</div>
</div>
Here's the working form for a new Organization/User combo:
<% provide(:title, 'Sign up') %>
<div class="container-fluid">
<h1>Sign up!</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="well">
<%= form_for(#organization, :html => {:class => "form-horizontal"}) do |f| %>
<%= render 'shared/org_error_messages' %>
<div class="form-group">
<%= f.label :organization_name, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= f.text_field :organization_name, :placeholder => "Who do you work for?" %>
</div>
</div>
<%= f.fields_for :users, #organization.users_for_form do |user| %>
<div class="form-group">
<%= user.label :name, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= user.text_field :name, :placeholder => "What's your name?" %>
</div>
</div>
<div class="form-group">
<%= user.label :email, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= user.text_field :email, :placeholder => "Email" %>
</div>
</div>
<div class="form-group">
<%= user.label :password, :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= user.password_field :password, :placeholder => "Enter password - minimum 6 characters" %>
</div>
</div>
<div class="form-group">
<%= user.label :password_confirmation, "Repeat Password", :class => "col-md-4 control-label" %>
<div class ="col-md-8">
<%= user.password_field :password_confirmation, :placeholder => "Repeat password" %>
</div>
</div>
<%= user.hidden_field :organization_id, input_html: {value: #organization.id} %>
<% end %>
<%= f.submit "Create my account", class: "btn btn-large btn-success" %>
<% end %>
</div>
</div>
</div>
<div>
Where am I going wrong?
EDIT - here is the log from my console when the above happens:
Processing by UsersController#new as HTML
Parameters: {"organization_id"=>"1"}
Rendered shared/_error_messages.html.erb (0.1ms)
Rendered users/new.html.erb within layouts/application (3.4ms)
Rendered layouts/_shim.html.erb (0.0ms)
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'b8cabbe1e1514f14be24f95d48248ad716e11342' LIMIT 1
Organization Load (0.3ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT 1 [["id", 1]]
Rendered layouts/_header.html.erb (3.9ms)
Rendered layouts/_footer.html.erb (0.2ms)
Completed 200 OK in 28ms (Views: 26.0ms | ActiveRecord: 0.9ms)
Started POST "/organizations/1/users" for 127.0.0.1 at 2014-10-05 22:22:15 +0630
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"fKx7bdWtC7bmBKMRF3ivwBlmJXzrcWJ16dYYOfNLBC0=", "user"=>{"name"=>"", "email"=>"", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Add new user account", "organization_id"=>"1"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'b8cabbe1e1514f14be24f95d48248ad716e11342' LIMIT 1
Organization Load (0.4ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT 1 [["id", 1]]
(0.3ms) BEGIN
User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('') LIMIT 1
(0.8ms) COMMIT
Redirected to http://0.0.0.0:3000/organizations/1
Completed 302 Found in 14ms (ActiveRecord: 2.7ms)
Started GET "/organizations/1" for 127.0.0.1 at 2014-10-05 22:22:15 +0630
Processing by OrganizationsController#show as HTML
Parameters: {"id"=>"1"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'b8cabbe1e1514f14be24f95d48248ad716e11342' LIMIT 1
Organization Load (0.4ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT 1 [["id", 1]]
CACHE (0.0ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT 1 [["id", "1"]]
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."organization_id" = $1 [["organization_id", 1]]
Rendered organizations/_users_index.html.erb (1.0ms)
Organization Load (0.4ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT 1 [["id", 1]]
Company Load (0.6ms) SELECT "companies".* FROM "companies" WHERE "companies"."organization_id" = $1 [["organization_id", 1]]
Competitor Load (0.4ms) SELECT "competitors".* FROM "competitors" WHERE "competitors"."organization_id" = $1 [["organization_id", 1]]
Product Load (0.4ms) SELECT "products".* FROM "products" WHERE "products"."organization_id" = $1 [["organization_id", 1]]
Rendered organizations/show.html.erb within layouts/application (13.3ms)
Rendered layouts/_shim.html.erb (0.0ms)
Rendered layouts/_header.html.erb (0.6ms)
Rendered layouts/_footer.html.erb (0.2ms)
Completed 200 OK in 37ms (Views: 30.6ms | ActiveRecord: 3.1ms)
I think it's something to do with the way I'm handling creating a new user, after further testing. The following code is almost certainly where the error lies:
def create
if signed_in?
#organization = Organization.find(params[:organization_id])
#organization.users.create(user_params)
flash[:success] = "You added a new user to your organization. Send them their login details today!"
redirect_to #organization
else
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Thanks for signing up with My App! This is your profile page, be sure to take a look at the support link in the footer"
redirect_to #user
else
render 'new'
end
end
end
Where I'm testing if the User is signed in, the choice either leads to adding a new user to the current organization or creating both from scratch. What I need is a way to test whether #organization.users.create was successful (or maybe I need #organization.users.new) and if it fails the validations then I need to render "users/new" rather than heading back to the #organization path and displaying the (obviously incorrect) flash that a new user has been created.
Anyone got any ideas how I test for this? I tried a quick if/else test (along the lines of "if #organization.users.create ... else: render the users/new page"), but then I got a bunch of form errors because I wasn't defining the object that the page was creating.
I solved this with the change to the create function in the Users controller - I was creating a new #organization.user regardless of the error messages in the form. Instead I needed to use #user = #organization.users.new, and then use the same if #user.save ... test that works for a new user. See the below code for how it was fixed:
def create
if signed_in?
#organization = Organization.find(params[:organization_id])
#user = #organization.users.new(user_params)
if #user.save
flash[:success] = "You added a new user to your organization. Send them their login details today!"
redirect_to #organization
else
render 'new'
end
else
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Thanks for signing up with My App! This is your profile page, be sure to take a look at the support link in the footer"
redirect_to #user
else
render 'new'
end
end
end
I have implemented an oath object oriented approach to my rails application using this tutorial. I've also split my User Form into an Edit & Account Form.
User Edit Form
-Name
-Username
-AboutMe
User Account Form
-Email
-Password
-Password Confirmation
Everything seems to be working okay, until I try to Edit a Regular User's Account or Profile. For some reason I keep getting this error.
undefined method `regular_user_path' for #<#<Class:0x007fc1952f6da0>:0x007fc18bf350a8>
I am not sure why this may be happening. Here is my code below.
Models
class User < ActiveRecord::Base
attr_accessible :name, :bio, :avatar, :username
end
class RegularUser < User
has_secure_password
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
VALID_UNAME_REGEX = /^[a-z](\w*[a-z0-9])*$/i
validates :name, length: { maximum: 50 }
validates :username, :presence => true,
:length => { :maximum => 15 },
:format => { :with => VALID_UNAME_REGEX },
:uniqueness => { :case_sensitive => false }
validates :bio, length: { maximum: 50 }
end
Controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :profile, :update, :destroy, :following, :followers, :account]
before_filter :correct_user, only: [:edit, :update, :account]
before_filter :admin_user, only: [:destroy]
def edit
#user = User.find_by_username(params[:id])
end
def account
#title = "Account"
#user = User.find_by_username(params[:id])
end
def update
#user = RegularUser.find(current_user.id) ###I think this is causing it
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to root_url
else
if URI(request.referer).path == edit_user_path ###redirects to appropriate page
render 'edit'
else
render 'account'
end
end
end
def destroy
User.find_by_username(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_url
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to (root_path), notice: "Please sign in."
end
end
def correct_user
#user = User.find_by_username(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
Views
Edit View
<%= form_for #user, :html => { :multipart => true } do |f| %> ###error comes from this line
<%= render 'shared/error_messages', object: f.object %>
<div class="statictitle">Your Profile</div>
<%= f.text_field :username, placeholder: "Username..", :class => "form-control" %>
<%= f.text_field :name, placeholder: "Name", :class => "form-control" %>
<%= f.text_area :bio, placeholder: "About yourself in 160 characters or less...", class: "textinput" %>
<%= f.submit "Update Profile", class: "btn btn-primary" %><br>
<% end %>
Shared Errors
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Routes
resources :users do
member do
get :account
end
end
LOGS
Started PUT "/users/ClickOnComics" for 127.0.0.1 at 2014-02-20 17:17:50 -0800
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"1CUMHhkE10ubS6uuc26fu1yTGn1bABKNqRIJ67EhEO4=",
"user"=>{"email"=>"clickoncomics#gmail.com", "password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}, "commit"=>"Update Account", "id"=>"ClickOnComics"}
User Load (0.9ms) SELECT "users".* FROM "users"
WHERE "users"."remember_token" = 'Wqodv-nd6EhKseqQf9FhqA' LIMIT 1
User Load (1.1ms) SELECT "users".* FROM "users"
WHERE "users"."username" = 'ClickOnComics' LIMIT 1
RegularUser Load (0.5ms) SELECT "users".* FROM "users"
WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
(0.2ms) BEGIN
RegularUser Exists (2.7ms) SELECT 1 AS one FROM "users" WHERE
(LOWER("users"."username") = LOWER('ClickOnComics') AND "users"."id" != 1)
LIMIT 1
RegularUser Exists (2.7ms) SELECT 1 AS one FROM "users"
WHERE (LOWER("users"."email") = LOWER('clickoncomics#gmail.com') AND "users"."id" != 1) LIMIT 1
(0.2ms) ROLLBACK
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."username" = 'ClickOnComics' LIMIT 1
Completed 500 Internal Server Error in 237ms
NoMethodError (undefined method `errors=' for #<User:0x007fb6fadf87d0>):
app/controllers/users_controller.rb:40:in `update'
In your update action do as suggested below :
def update
#user = RegularUser.find(current_user.id)
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to root_url
else
error_messages = #user.errors.messages ### Capture the error messages
#user = User.find_by_username(params[:id]) ### Add this line
#user.errors.messages.merge!(error_messages) ### Set the error messages hash
if URI(request.referer).path == edit_user_path
render 'edit'
else
render 'account'
end
end
end
When your update fails, you need to reset #user to User instance otherwise when you render edit view it will receive RegularUser instance rather than User instance whereas your form is expecting User instance.
Try adding resources :regular_users to your routes.rb file