I am using nested forms to insert data into two tables (user and address).I want to have my users email id in both the table, but the user should enter the email id once. Here is my current view
<%= form_for #user do |f| %>
<%= f.text_field(:name, :size => 20) %>
<%= f.text_field(:email, :size => 20) %>
<%= f.fields_for :address do |r| %>
<%= r.text_field(:street, :size => 20) %>
<%= r.text_field(:city, :size => 20) %>
<% end %>
<%= f.submit "Create" %>
<% end %>
In my nested section "address" i once again want the email field, but i don't want a repeated text field for email. How can i use the email section inside the nested form "address"? I have tried using hidden form fields, but it didn't worked. Can somebody help please.
EDIT
Controller(Only question related parts)
class UsersController < ApplicationController
def new
#domain = Domain.find(params[:id])
#user = #domain.users.build
#title = "Add User"
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Welcome!"
redirect_to manageDomain2_path(:id => #user.domain_id)
else
#title = "Add User"
redirect_to addNewUser_path(:id => #user.domain_id)
end
end
I have tried with:
#user = User.new(params[:user][:address_attributes].merge!(:email => params[:user][:email]))
When using:
#user = User.new(params[:user][:address].merge!(:email => params[:user][:email]))
I am getting error "Undefined method merge".
User Model (Question related portion only)
class User < ActiveRecord::Base
attr_accessible: :email, :domain_id, :address_attributes
belongs_to :domain
has_one :address
accepts_nested_attributes_for :address
end
Address Model (Full)
class Address < ActiveRecord::Base
attr_accessible :user_id, :email, :street, :city
end
When i use
belongs_to :user
in address model i get syntax error. So i have tried without using it. the user_id, street, city is getting proper values but email email field is not getting any thing.
You can just add it to the params hash from your controller:
params[:user][:address].merge!(:email => params[:user][:email])
Related
I have simple app with 3 tables in DB and 'many-to-many' relationships.
# Model Employee
class Employee < ActiveRecord::Base
has_and_belongs_to_many :phonenumbers
accepts_nested_attributes_for :phonenumbers, :allow_destroy => true
attr_accessible :last_name, :first_name, :middle_name, :phonenumbers_attributes
end
# Model Phonenumber
class Phonenumber < ActiveRecord::Base
has_and_belongs_to_many :employees
attr_accessible :number
accepts_nested_attributes_for :employees
end
I have 'employees_phonenumbers' join-table with 'employee_id' and 'phonenumber_id' columns.
# View
<%= form_for #employee, :url => { :action => :create } do |f| %>
<%= f.label "Last name" %>
<%= f.text_field :last_name %>
<%= f.label "First name" %>
<%= f.text_field :first_name %>
<%= f.label "Middle name" %>
<%= f.text_field :middle_name %>
<%= f.fields_for :phonenumbers do |phonenumber| %>
<%= phonenumber.label "Phone number" %>
<%= phonenumber.telephone_field :number %>
<% end %>
<%= f.submit "Create" %>
<% end %>
# Controller
def create
#employee = Employee.new(params[:employee])
#employee.save ? (redirect_to :action => :index) : (render "new")
end
Now if I create a user: 'John' with phone number '555', it's OK.
But if I want to create a user 'Larry' with the same phone number '555', there's a dublicate of '555' entry in the DB.
How do I prevent this?
UPDATE: My logic is: If there is number '555', then do not create a new one, use existing. If there is no such a number, then create a new one and use it.
in employee.rb:
before_save :get_phonenumbers
def get_phonenumbers
self.phonenumbers = self.phonenumbers.collect do |phonenumber|
Phonenumber.find_or_create_by_number(phonenumber.number)
end
end
I have found its working
You can use rails validation to check uniqueness of record.
In your model phonenumber.rb put following line,
validates_uniqueness_of :column_name
It will ensure that Phonenumber will have unique phone_numbers only.
Now in controller you can check phone_number from params and if number is already exist then we will delete nested attributes fron params so that Phonenumber record wont generate.
def create
#phone_number = Phonenumber.where(:number=>params[:employee][:phonenumber][:number])
if #phone_number.any?
params[:employee].delete(:phonenumber)
#employee = Employee.new(params[:employee])
if #employee.save?
#employee.phonenumber = #phone_number.first
redirect_to :action => :index
else
render "new"
end
else
#employee = Employee.new(params[:employee])
#employee.save ? (redirect_to :action => :index) : (render "new")
end
end
I'm rather new to Rails and I'm writing a signup form that includes nested models. When I submit the form, the user is saved just fine, but the nested model does not save anything to the Subscription db, and the console throws no errors.
I sincerely hope I'm not missing something insanely obvious, and I appreciate any tips you can share. Thanks!
Here is the code-
Models:
class Plan < ActiveRecord::Base
attr_accessible :posts, :name, :price
has_many :users
end
class User < ActiveRecord::Base
belongs_to :plan
has_many :events
has_one :subscription, :autosave => true
accepts_nested_attributes_for :subscription
attr_accessible :subscription_attributes
def save_with_payment
if valid?
customer = Stripe::Customer.create(
email:email,
plan: plan_id,
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
end
class Subscription < ActiveRecord::Base
attr_accessible :plan_id, :status, :user_id
belongs_to :user
end
This is the User controller:
def new
#user = User.new
plan = Plan.find(params[:plan_id])
#user = plan.user
#user.build_subscription
end
def create
#user = User.new(params[:user])
if #user.save_with_payment
sign_in #user
flash[:success] = "Welcome to the SendEvent!"
redirect_to #user
else
render 'new'
end
end
This is the form:
<%= form_for #user, :html => {:class => "form-inline"} do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="control-group">
<%= f.label :name, :class => "control-label" %>
<%= f.text_field :name %>
</div>
# A few more fields here and...
# The nested model:
<%= f.fields_for :subscription do |builder| %>
<%= builder.hidden_field :status, :value => true %>
<% end %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary", id: "submitacct" %>
<% end %>
Sample app from RailsCasts
RailsCasts Episode #196: Nested Model Form (revised)
Maybe help you.
I have the models User and Group, and the join table Membership which uses has_many :through method. In my join table's form, I want the user to input a valid group name that an administrator has created to become a member of that group.
I have gotten the case where a valid name is entered to work but now I need some validation if they input a blank text box, or that the inputted group name exists in the database, I'd like some nice error messages. I thought this would be possible through some validates method?
membership partial _form.html.erb
<%= form_for(#membership) do |f| %>
<% if #membership.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#membership.errors.count, "error") %> prohibited this membership from being saved:</h2>
<ul>
<% #membership.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :group %><br />
<%= f.text_field :group %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
membership.rb
class Membership < ActiveRecord::Base
belongs_to :group
belongs_to :user
attr_accessible :user_id, :group_id
validates_uniqueness_of :group_id, :message => "can be only joined once", :scope => 'user_id'
validates_presence_of :group, :user
end
group.rb
class Group < ActiveRecord::Base
has_many :memberships, :dependent => :destroy
has_many :users, :through => :subscriptions
validates :name, :presence => true, :uniqueness => true
attr_accessible :name, :expiry
end
So need some direction as how the validation happens because the above validation in the membership and group models doesn't work, I get the error for both empty text box or name not in the database...
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Edit: Added controller code below
def create
#group = Group.find_by_name(params[:membership][:group])
#membership = current_user.memberships.build(:group_id => #group.id)
respond_to do |format|
if #membership.save
format.html { redirect_to membership_url, :notice => 'Membership was successfully created.' }
format.json { render :json => #membership, :status => :created, :location => #membership }
else
format.html { render :action => "new" }
format.json { render :json=> #membership.errors, :status => :unprocessable_entity }
end
end
end
Add the following to your group model:
validate_uniqueness_of :name, :message => "a group already exists with that name"
validate_presence_of :name
The validations are called for all tables you are inserting to.
Edit:
Change your controller like this:
#membership = current_user.memberships.build(:group => #group)
You won't get the id called on nil error anymore. And if #group is nil, the validation in your membership will pick it up on the save attempt.
I solved this question by changing the text input box to a select field, and will add a password field to the model to solve my issue of unwanted users joining the group.
def create
#groups = Group.current
#group = Group.find_by_name(params[:membership][:group])
#membership = current_user.memberships.build(:group_id => #group.id)
After which my model validation works now below
validates_uniqueness_of :group_id, :message => "can be only be joined once", :scope => 'user_id'
I have a form attached to profiles where short comments can be submitted. I want to capture the author's name though so I can display it in a tooltip when hovering over the comment's body.
In my create method in the controller I have:
def create
#comment = Comment.new(params[:comment])
#comment.save!
redirect_to profile_path(#comment.profile)
end
Inside my migration:
t.timestamps
t.integer :profile_id
t.string :author_id
t.string :body
Profile model:
belongs_to :user
accepts_nested_attributes_for :user
has_many :comments
Comment model:
belongs_to :profile
ProfilesController:
def show
#user = User.find(params[:id])
#profile = user.profile
#superlative = #profile.superlatives.new
end
And my form:
<%= form_for #comment do |f| %>
<%= f.hidden_field :profile_id, :value => #profile.id %>
<%= f.hidden_field :author_id, :value => "#{current_user.profile.first_name} #{current_user.profile.last_name}" %>
<%= f.text_field :body %>
<%= f.submit 'Add new' %>
<% end %>
I was thinking of linking the :author_id to current_user.profile.id and using that association to display :first_name and :last_name which are attributes of the profile. Or is there a simpler, better way?
UPDATE: I got it to display the name though I'm still curious if there's a better way.
Your solution looks fine, but I'd store the User (or whatever class current_user returns) instead of the Profile:
In app/models/comment.rb:
class Comment < ActiveRecord::Base
belongs_to :profile
belongs_to :author, :class_name => "User", :foreign_key => "author_id"
... rest of the code ...
end
You then change your migration to:
t.integer :author_id
and your controller method to:
def create
#comment = Comment.new(params[:comment].merge(:author_id => current_user.id))
#comment.save!
redirect_to profile_path(#comment.profile)
end
In your view (I used the title attribute do create a tooltip, but feel free to use whatever method you like):
<div class="comment" title="<%= #comment.author.profile.first_name %> <%= #comment.author.profile.last_name %>">
<%= #comment.body %>
</div>
I would suggest something like this:
In your routes.rb create a nested resource for comments
resources :users do
resources :comments
end
In your User model
class User
has_many :comments
end
In your Comment model
class Comment
belongs_to :user
end
In your CommentsController in the new and create methods
#comment = User.find(params[:user_id]).comments.new(params[:comment])
So the comment automagically gets created as belonging to that User and you don't have to pass anything around.
Then, in your Comment view, you could just call its owners name
#comment.user.first_name
I have a Member model that belongs to User
class Member < ActiveRecord::Base
attr_accessible :name
belongs_to :user
end
class User < ActiveRecord::Base
attr_accessible :name
has_many :members, :dependent => :destroy
end
In my Members controller I have
class MembersController < ApplicationController
def create
#user = User.find(params[:user_id])
#member = #user.members.build(params[:member])
if #member.save
flash[:success] = "Member created!"
redirect_to root_path
else
render 'pages/home'
end
end
end
In /app/views/users/show.html.erb I have
<%= form_for #member do |f| %>
<div class="field">
<%= f.text_area :name %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
But I get the following error:
undefined method `model_name' for NilClass:Class
Extracted source (around line #18):
15:
16: <h1 class="member">What's up?</h1>
17:
18: <%= form_for #member do |f| %>
My show action in the Users controller is
def show
#user = User.find(params[:id])
#members = Member.new
#title = #user.name
end
Which also contains the 'new' method
I have tried changing :user_id to :id in the MembersController but this does not work either. What am I doing wrong here?
thanks in advance
Try to replace #members = Member.new by #member = Member.new ;-) !
I needed to pass the #user.id as a hidden field in the form, for the association to work!