I'm new in rails and currently trying to create an app but I can't seem to make it work. Here's my setup in model.
class User < ActiveRecord::Base
has_one :doctor, dependent: :destroy
accepts_nested_attributes :doctor
end
class Doctor < ActiveRecord::Base
belongs_to :user, :dependent => :destroy
end
In my users_controller, here's my code:
class UsersController < ApplicationController
def show
#user = current_user
# render text: #user.inspect
end
def new
#user = User.new
#user.build_doctor`
end
def create
# binding.pry
#user = User.new(user_params)
if #user.save
sign_in #user
redirect_to dashboard_path
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:role, :lastname, :firstname, :middlename, :email, :password, :password_confirmation, :doctor_attributes => [:institution, :license_number])
end
end
And my view:
<ul id="cbp-bislideshow" class="cbp-bislideshow">
<li>
<%= image_tag "blur1.jpg" %>
</li>
<li>
<%= image_tag "blur2.jpg" %>
</li>
</ul>
<% provide(:title, 'Sign Up') %>
<%= form_for(#user) do |f| %>
<div class="sign-up-wrapper divided-wrapper cf">
<div class="left-section">
<h3 class="section-title">JOIN US AND LET'S CHANGE THINGS</h3>
<div class="row">
<div class="w49 pull-left">
<%= f.text_field :firstname, class: "input-text personal ", placeholder: 'FIRSTNAME' %>
</div>
<div class="w49 pull-right">
<%= f.text_field :lastname, class: "input-text personal", placeholder: 'LASTNAME' %>
</div>
<%= f.hidden_field :role, value: :doctor %>
</div>
<div class="row">
<%# f.text_field :specialization, class: "input-text personal ", placeholder: 'SPECIALIZATION' %>
</div>
<%= f.fields_for :doctors do |p| %>
<div class="row">
<%= p.text_field :institution, class: "input-text personal ", placeholder: 'INSTITUTION' %>
</div>
<div class="row">
<%= p.text_field :license_number, class: "input-text personal ", placeholder: 'LICENSE NUMBER' %>
</div>
<% end %>
<span class="remind bottom-message"> ONCE INSIDE DON'T FORGET TO UPDATE YOUR PROFILE WITH MORE DETAILS </span>
</div>
<div class="right-section">
<h3 class="section-title"></h3>
<div class="row">
<%= f.text_field :email, class: "input-text personal ", placeholder: 'EMAIL' %>
</div>
<div class="row">
<%= f.password_field :password, class: "input-text personal ", placeholder: 'PASSWORD' %>
</div>
<div class="row">
<%= f.password_field :password_confirmation, class: "input-text personal ", placeholder: 'CONFIRM PASSWORD' %>
</div>
<div class="row cf">
<%= f.submit class: 'btn-join btn', value: 'JOIN NOW' %>
</div>
<div class="row">
SIGN UP WITH FACEBOOK / TWITTER ACCOUNT?
</div>
</div>
</div>
<% end %>
Everytimie I execute these pieces, only the user model gets populated but not the doctors table? Is there something wrong on my code?
EDIT
Changed doctors_attributes to doctor_attributes
changed #user.doctor.build`to #user.build_doctor
In the logs. I saw this error ---> Unpermitted parameters: doctors
So in theory, I think we know what's the problem, but I don't know how to fix this in the strong_parameters. Haven't tried a strong_parameter with accepted_nested_attributes_for in rails yet and this is my first time. Any solution?
In the fields_for, replace :doctors with :doctor. Remember that you're doing a 1 to 1 relationship.
In your user_params model, the attribute doctors_attributes should be doctor_attributes since it's a has_one relationship. If it was a has_many relationship, it would be doctors_attributes. The part before _attributes would be whatever the association is named.
Another note: If you want to be able to update the doctor from the user form, you should also include the id in the doctor_attributes array. Though now that I think of it, it might only be a requirement on has_many nested associations. I've never tried doing a has_one without including the id.
Related
I'm trying to create a DRY form that I could use as form_fields for other, nested forms in different view. I'm having 2 problems.
I want the _form partial to not have a submit button, and rather have this button on the form itself. However, clicking the submit button in it's current place doesn't do anything??
The form displays fine in it's current state. If I move the submit button to the _form just to see that it saves, I get a routing error for uninitialized constant UsersController?
My code:
routes.rb
devise_for :users
resources :users do
resources :projects
end
user.rb model - I'm using Devise.
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
validates :password, :presence => true,
:on => :create,
:format => {:with => /\A.*(?=.{8,})(?=.*\d)(?=.*[\#\#\$\%\^\&\+\=]).*\Z/ }
has_many :projects, inverse_of: :user
accepts_nested_attributes_for :projects
end
projects.rb model
class Project < ApplicationRecord
belongs_to :user, inverse_of: :projects
...
end
projects_controller.rb
class ProjectsController < ApplicationController
...
def new
#project = current_user.projects.build
end
def create
#project = current_user.projects.new(project_params)
if #project.save
redirect_to root_path, notice: 'Your project is being reviewed. We will be in contact soon!'
else
render :new
end
end
...
private
...
def project_params
params.require(:project)
.permit(
:user_id, :project_type_id, :name, :industry_id,
:description, :budget_id, :project_status_id, feature_ids:[], addon_ids:[]
)
end
end
_form.html.erb partial view
<%= form_for #project do |f| %>
<div class="project_form">
<ol>
<div class="field entry_box">
<li><%= f.label "Give your project a name" %>
<%= f.text_field :name, placeholder: "A short name", class: "form-control entry_field" %></li>
</div>
...... # All of the other form fields
<div class="field entry_box">
<li><%= f.label "What budget do you have in mind?" %>
<%= collection_select(:project, :budget_id, Budget.all, :id, :list_of_budgets, {include_blank: 'Please select'}, {class: "form-control entry_field"} ) %></li>
</div>
</ol>
# No f.submit button -> moved to view
</div>
<% end %>
new.html.erb view for new projects
<div class="container">
<div class="center">
<h1>New Project</h1>
</div>
<%= form_for current_user do |f| %>
<%= f.fields_for #project do |builder| %>
<%= render 'form', :locals => { f: builder } %>
<% end %>
<div class="actions center space_big">
<%= f.submit "Save Project", class: "btn btn-lg btn-success" %>
</div>
<% end %>
</div>
How do I get the submit button in it's current position to work?
What's causing the routing error for uninitialized constant UsersController?
In your _form partial you dont need the first line i.e form_for since you have already passed f which is a form ('builder') object for projects since you created it inside of fields_for #project block.
so this much will do:
<div class="project_form">
<ol>
<div class="field entry_box">
<li><%= f.label "Give your project a name" %>
<%= f.text_field :name, placeholder: "A short name", class: "form-control entry_field" %></li>
</div>
...... # All of the other form fields
<div class="field entry_box">
<li><%= f.label "What budget do you have in mind?" %>
<%= collection_select(:project, :budget_id, Budget.all, :id, :list_of_budgets, {include_blank: 'Please select'}, {class: "form-control entry_field"} ) %></li>
</div>
</ol>
# No f.submit button -> moved to view
</div>
and in your form_for current_user change render line to like this:
<%= render partial: 'form', :locals => { f: builder } %>
and you are getting that controller error since you dont have UsersController and you are making the nested_form for a User that is current_user so you should have this code inside UsersController's new action and build a project for user there.
I'm trying to render this code (partial to update users payment info).
/devise/registrations/_credit.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<form action="#">
<div class="form-group">
<label class="control-label">Card Holder Name</label>
<%= f.text_field :name, autofocus: true, class:"form-control" %></div>
<div class="form-group">
<label class="control-label">Card Number</label>
<%= f.text_field :card, autofocus: false, class:"form-control" %>
</div>
<div class="form-group">
<label class="control-label">CVV</label>
<%= f.text_field :cvv, autofocus: false, class:"form-control" %>
</div>
<div class="form-group">
<label class="control-label">Expiration Month</label>
<%= f.text_field :expmonth, autofocus: false, class:"form-control" %>
</div>
<div class="form-group">
<label class="control-label">Expiration Year</label>
<%= f.text_field :expyear, autofocus: false, class:"form-control" %>
</div>
<div class="margin-top-10">
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="actions">
<%= f.submit "Update", class:"btn green" %>
<% end %>
</div>
</form>
</div>
I'm trying to get this partial to show up in a different page that's not under users_controller.rb, but I keep getting an error.
NameError in Orders#new
Showing /home/nitrous/code/uvesty/app/views/devise/registrations/_credit.html.erb where line #2 raised:
undefined local variable or method `resource' for #<#<Class:0x00563138834928>:0x00563138821670>
In app/models/order.rb:
class Order < ActiveRecord::Base
belongs_to :user
# only use this if user instance is created before order,
# and alway associated with order
validates :user, presence: true
end
In app/models/user.rb:
class User < ActiveRecord::Base
has_many :orders
# --OR--
# has_one :order
end
In app/controllers/orders_controller.rb:
class OrdersController < ApplicationController
# 1)assuming `current_user` is populated
#
def new
#order = Order.new
#user = current_user
end
# --OR--
# 2) assuming the following line is in `config/routes.rb`:
# get '/orders/new/:id' => 'orders#new'
#
def new
if #order = Order.find_by_id(new_params[:id])
#user = #order.user
else
# do whatever here; replace the next line
raise "order not found"
end
end
private
# only needed for 2) above
def new_params
params.permit(:id)
end
end
see: http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
In app/view/orders/new.html.erb:
<% raise('#user not defined') unless #user %><%# <- Remove this line after partial is working %>
<%= render partial: "devise/registrations/credit", locals: {resource: #user, resource_name: :user} %>
see: http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
Forced to ask for help with saving nested models on polymorphic association. I'm missing something but can't figure out what.
Everithing pretty straightforward. There is Address which can have multiple Phones.
So models are
class Address < ActiveRecord::Base
has_many :phones, as: :phoneable
accepts_nested_attributes_for :phones, allow_destroy: true
validates :city, :street, :building, :name, presence: true
end
and
class Phone < ActiveRecord::Base
belongs_to :phoneable, polymorphic: true
validates :number, :extension, presence: true
end
addresses_controller.rb
def new
#address = Address.new
#phone = #address.phones.build
authorize #address
end
def create
#address = Address.create(address_params)
authorize #address
if #address.save
binding.pry
flash[:success] = "Address #{#address.name} created"
redirect_to address_path(#address)
else
flash.now[:danger] = 'Failed'
render :new
end
end
def address_params
params.require(:address).permit(:name, :street, :building, :city, phones_attributes: [:id, :number, :extension, :details] )
end
/app/views/address.html.erb
<div class="row">
<div class="col-md-12">
<%= form_for(#address, html: {class: 'form-horizontal', role: 'form'}) do |f| %>
<%= render 'shared/errors', obj: #address, model_name: 'addresses' %>
<div id="create-form">
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :city, 'Город' %>
</div>
<div class="col-md-4">
<%= f.select(:city, options_for_select(['Moscow', 'Samara']), {}, {class: "form-control"}) %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :street, 'Street' %>
</div>
<div class="col-md-4">
<%= f.text_field :street, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :building, 'Building' %>
</div>
<div class="col-md-4">
<%= f.text_field :building, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :name, 'Place name' %>
</div>
<div class="col-md-4">
<%= f.text_field :name, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= f.label :phones, 'Phone' %>
</div>
<div class="col-md-4">
<%= f.fields_for :phone do |phone_form| %>
<%= phone_form.text_field :number, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="control-label col-md-4">
<%= phone_form.label :extension, 'Ext.' %>
</div>
<div class="col-md-4">
<%= phone_form.text_field :extension, class: 'form-control' %>
</div>
<% end %>
</div>
<div class="form-group">
<div class='col-md-offset-4 col-md-6'>
<%= f.submit #address.new_record? ? 'Add' : 'Update', class: 'btn btn-primary btn-md' %>
</div>
</div>
</div>
<% end %>
</div>
</div>
First issue I encountered with is if I set key :phones instead :phone into the following line <%= f.fields_for :phone do |phone_form| %> my phone text fields don't render in view but they should. One user emphasized this moment here https://stackoverflow.com/a/3328041/2049476
if I use :phone everything somehow works fine but seems like it's wrong.
And the second one.
Phone object doesn't save in DB, when I create new address or edit current I succeed but phone doesn't show any validation errors if I leave all it fields blank.
Here what I have in params hash
{"utf8"=>"✓",
"authenticity_token"=>"inwXr3Ev/Aj/hZRY2IadizDHDgdSFo2zFhY9DAvysfFu3jjD9AS66esKVsTzEuKo2WC46YQt6HnOKTgInvfUEg==",
"address"=>{"city"=>"Moscow", "street"=>"ul. Tsentralnaya d. 4 kv. 220", "building"=>"1212", "name"=>"Astoria", "phone"=>{"number"=>"9215555555", "extension"=>"111"}},
"commit"=>"Add",
"controller"=>"addresses",
"action"=>"create"}
What am I missing?
Try answer for 2 issues:
The correct way is to pass :phones, and then phone as variable to field_for, like is was done here:
<%- #address.phones.each.with_index do |phone, index| %>
<%- f.fields_for :phones, phone do |phone_form| %>
<%- end %>
<%- end %>
Should be resolved as of the 1-st question, since the fields shoudl sent ot server via params not a phone hash, but phones_attributes array of hashes, in order to accepts_nested_attributes_for could accept phones:
phones_attributes: [{ ... },{ ... }]
I am creating an application through which a user will be able to create an account. When they create an account, in the same form they will be able to create an organization that will then be tied to their user. Once that user has created their account (and an organization) other users will be able to create an account and use an "access code" to join that organization as well. Looking at the code may explain it better.
The reason i'm posting on SO is because i have a feeling there is a better / more efficient way to do it than what i am currently doing. I'm using nested_forms (maybe not correctly) and i don't think i'm doing the associations the right way because, for example, i haven't been able to get the edit form to fill out the organization fields.
I am using sorcery for the authentication as well.
users_controller.rb
def new
#user = User.new
end
def create
#user = User.new(user_params)
if params[:user][:organization][:name].blank?
flash.now[:error] = "You must specify an organization name."
render :new
else
if params[:user][:organization][:access_code].blank?
# create new organization
#access_code = "#{SecureRandom.urlsafe_base64(16)}#{Time.now.to_i}"
#organization = Organization.create(:name => params[:user][:organization][:name], :access_code => #access_code)
#user.organization_id = #organization.id
#user.is_admin = true
else
# try and add someone to an organization
#organization = Organization.find(:all, conditions: ["name = ? AND access_code = ?", params[:user][:organization][:name], params[:user][:organization][:access_code]])
if #organization.empty?
flash.now[:error] = "No organization has been found with that name and access code."
render :new
return
else
#user.organization_id = #organization.first.id
end
end
if #user.save
user = login(#user.email, params[:user][:password])
if user
flash[:success] = "Your account has been successfully created!"
redirect_to admin_dashboard_path
end
else
flash.now[:error] = "Something went wrong! Please try again."
render :new
end
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.is_admin?
if params[:user][:organization][:name].blank? && params[:user][:organization][:name] != #user.organization.name
params[:user][:organization][:name] = #user.organization.name
end
if params[:user][:organization][:access_code].blank? && params[:user][:organization][:access_code] != #user.organization.access_code
params[:user][:organization][:access_code] = #user.organization.access_code
end
#organization = Organization.find(params[:user][:organization_id])
#organization.name = params[:user][:organization][:name]
#organization.access_code = params[:user][:organization][:access_code]
#organization.save
end
if #user.update(user_params)
flash[:success] = "Your settings have been updated!"
redirect_to edit_admin_user_path(#user.id)
else
flash.now[:error] = "Something went wrong! Please try again."
render :edit
end
end
private
def user_params
params.require(:user).permit(:organization_id, :email, :password, :password_confirmation, :full_name, :remember_me, {:organization_attributes => [:name, :website, :description, :access_code]})
end
users.rb
class User < ActiveRecord::Base
authenticates_with_sorcery!
belongs_to :organization
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates_presence_of :full_name
validates_presence_of :email
validates_uniqueness_of :email, :on => :create
validates_format_of :email, :with => VALID_EMAIL_REGEX, :on => :create
validates_presence_of :password, :on => :create
validates_confirmation_of :password
end
organization.rb
class Organization < ActiveRecord::Base
authenticates_with_sorcery!
has_many :users, :dependent => :destroy
accepts_nested_attributes_for :users
validates_presence_of :name
end
new.html.erb
<% provide(:title, 'Create a User') %>
<h1>Create a User</h1>
<p>Use the form below to create an account.</p>
<%= nested_form_for([:admin, #user], html: {role: "form"}) do |f| %>
<%= render "shared/error_messages", obj: #user %>
<fieldset>
<legend>User Information</legend>
<div class="form-group">
<%= f.label :full_name, "Full Name" %>
<span class="help-block">How should others see you?</span>
<%= f.text_field :full_name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :email %>
<span class="help-block">Your email address is used as your login.</span>
<%= f.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: "form-control" %>
</div>
</fieldset>
<%= f.fields_for :organization do |o| %>
<fieldset>
<legend>Associated Organization</legend>
<div class="form-group">
<%= o.label :name, "Organization Name" %>
<span class="help-block">This is the name of the organization you are a part of.</span>
<%= o.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= o.label :access_code, "Organization Access Code" %>
<span class="help-block">Leaving this field blank will setup a new organization.</span>
<%= o.text_field :access_code, class: "form-control" %>
</div>
</fieldset>
<% end %>
<div class="form-actions">
<%= f.submit "Create Account", class: "btn btn-primary" %>
<%= link_to "Cancel", :back, class: "text-btn" %>
</div>
<% end %>
edit.html.erb
<% provide(:title, "Edit User: #{#user.full_name} (#{#user.organization.name})") %>
<h1>Edit User: <%= #user.full_name %> (<%= #user.organization.name %>)</h1>
<p>Use the form below to manage your account.</p>
<%= nested_form_for([:admin, #user], html: {role: "form"}) do |f| %>
<%= render "shared/error_messages", obj: #user %>
<fieldset>
<legend>User Information</legend>
<div class="form-group">
<%= f.label :full_name, "Full Name" %>
<span class="help-block">How should others see you?</span>
<%= f.text_field :full_name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :email %>
<span class="help-block">Your email address is used as your login.</span>
<%= f.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, placeholder: "leave blank to keep password unchanged", class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: "form-control" %>
</div>
</fieldset>
<% if #user.is_admin? %>
<%= f.fields_for :organization do |o| %>
<fieldset>
<legend>Associated Organization</legend>
<div class="form-group">
<%= o.label :name, "Organization Name" %>
<span class="help-block">This is the name of the organization you are a part of.</span>
<%= o.text_field :name, class: "form-control", value: #user.organization.name %>
</div>
<div class="form-group">
<%= o.label :access_code, "Organization Access Code" %>
<span class="help-block">Leaving this field blank will setup a new organization.</span>
<%= o.text_field :access_code, class: "form-control", value: #user.organization.access_code %>
</div>
</fieldset>
<% end %>
<%= f.hidden_field :organization_id %>
<% end %>
<div class="form-actions">
<%= f.submit "Update User", class: "btn btn-primary" %>
<%= link_to "Cancel", :back, class: "text-btn" %>
</div>
<% end %>
Ok, those are all the files making it happen. Now, i have the application doing almost everything i need it to do but this doesn't feel like production-level code to me.
One issue i know i am having is that if a user types something in the organization field and nothing else the controller will create and save the organization and then render the form back with the user validation errors. I don't want it to save the organization if there are validation errors in the user model.
I'm really just asking for advice if there is a better way of doing what i am trying to do. If you can't tell exactly what i'm trying to do with this code or have any questions please let me know!
Take a look at this post: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Of particular interest will be the section on "3. Extract Form Objects".
Ok I've searched far and wide and can't find a solution that I can get working...so I decided to post here.
I have 2 models
Store
class Store < ActiveRecord::Base
attr_accessible :storeimage, :storename
belongs_to :user
validates :user_id, :presence => true
end
and
User
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :userimage, :remove_userimage
has_secure_password
has_many :gears
has_many :comments, :dependent => :destroy
has_one :store, :dependent => :destroy
before_save :create_remember_token
require 'carrierwave/orm/activerecord'
mount_uploader :userimage, UserpicUploader
accepts_nested_attributes_for :store
...
end
When someone creates a new user account I need to automatically create a new store for that user I was thinking within the user form. So how can I create a new store object that's linked to the new user being created?
Here is my code from the User Controller for CreateAction
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to #user, :flash => {:success => "Welcome to Equiptme"}
else
render 'new'
#title = "Sign up"
end
end
View
<div class="signup_container">
<div class="signup_container_interior">
<%= provide(:title, 'Sign up') %>
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div>
<div>
The form contains <%= pluralize(#user.errors.count, "error") %>.
</div>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :first_name %> <%= f.text_field :first_name, class: 'register_text_area' %>
</div>
</div>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :last_name %> <%= f.text_field :last_name, class: 'register_text_area' %>
</div>
</div>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :email %> <%= f.text_field :email, class: 'register_text_area' %>
</div>
</div>
<!--************STORE FIELDS ************** -->
<!--************STORE FIELDS END ************** -->
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :password %> <%= f.password_field :password, class: 'register_text_area' %>
</div>
</div>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'register_text_area' %>
</div>
</div>
<div class="actions">
<%= f.submit "Create Account", class: 'register_button' %>
</div>
<% end %>
</div>
</div>
You can use the build_association method created along with the has_one relationship between users and stores:
def create
#user = User.new(params[:user])
#user.build_store
# etc
end
If you don't need the store until you've saved the user, you might also use create_association:
if #user.save
#user.create_store
# etc
end
You may want to take a look at this:
http://railscasts.com/episodes/196-nested-model-form-part-1