Displaying nested models - ruby-on-rails

My nested model form is now working, but I am having trouble displaying the data in a view. How do I display nested model data with a one-to-many relationship? Any help will be greatly appreciated.
Here's my form and controller:
<%= form_for #account do |f| %>
<%= f.label :account_type %><br />
<%= f.text_field :account_type %><br />
<%= f.fields_for :organizations do |builder| %>
<%= builder.label :name %><br />
<%= builder.text_field :name %><br />
<%= builder.label :website %><br />
<%= builder.text_field :website %><br />
<%= builder.fields_for :locations do |lb| %>
<%= lb.label :phone %><br />
<%= lb.text_field :phone %><br />
<%= lb.label :toll_free_phone %><br />
<%= lb.text_field :toll_free_phone %><br />
<%= lb.label :fax %><br />
<%= lb.text_field :fax %><br />
<%= lb.fields_for :addresses do |ab| %>
<%= ab.label :address1 %><br />
<%= ab.text_field :address1 %><br />
<%= ab.label :address2 %><br />
<%= ab.text_field :address2 %><br />
<%= ab.label :city %><br />
<%= ab.text_field :city %><br />
<%= ab.label :state %><br />
<%= ab.text_field :state %><br />
<%= ab.label :zip %><br />
<%= ab.text_field :zip %><br />
<% end %>
<% end %>
<% end %>
<%= f.submit "Add account" %>
<% end %>
class AccountsController < ApplicationController
def show
#account = Account.find(params[:id])
#organization = #account.organizations
end
def new
#account = Account.new
organization = #account.organizations.build
location = organization.locations.build
location.addresses.build
#header = "Create account"
end
def create
#account = Account.new(params[:account])
if #account.save
flash[:success] = "Account added successfully"
render 'show'
else
render 'new'
end
end
end
In general, how do I reference nested model data in a view when there is one-to-many relationship? Do I need to specify the child with some type of "where clause" like method?
Here is a simple example show.html.erb where I am trying to display the Name of the Organization that I just created. It doesn't work.
<h1><%= #organization.name %></h1>
The render 'show' action after creating an Account with the above form results in this error:
NoMethodError in Accounts#create
Showing C:/Documents and Settings/Corey Quillen/My
Documents/rails_projects/shop_manager/app/views/accounts/show.html.erb where line #1
raised:
undefined method `name' for nil:NilClass
Extracted source (around line #1):
1: <h1><%= #organization.name %></h1>
Rails.root: C:/Documents and Settings/Corey Quillen/My
Documents/rails_projects/shop_manager
Application Trace | Framework Trace | Full Trace
app/views/accounts/show.html.erb:1:in
`_app_views_accounts_show_html_erb__790921876_14235864__946051513'
app/controllers/accounts_controller.rb:21:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"y59rGAhS+kqfH3v3axhlYuxvBbBxIWXg0yucCFwfBq8=",
"account"=>{"account_type"=>"dfdf",
"organizations_attributes"=>{"0"=>{"name"=>"dfdf",
"website"=>"dfdf",
"locations_attributes"=>{"0"=>{"phone"=>"dfdf",
"toll_free_phone"=>"dfd",
"fax"=>"",
"addresses_attributes"=>{"0"=>{"address1"=>"",
"address2"=>"",
"city"=>"",
"state"=>"",
"zip"=>""}}}}}}},
"commit"=>"Add account"}

You say #organization = #account.organizations in your show action.
Just what are you expecting #organization to contain?
Think about it. It's going to be an array not a single organization so loop through that and get the name for each organization
Actually I think you haven't thought your relationships through properly surely an account belongs_to an organisation. Do you really want an account to be associated with more than one organisation ?
UPDATE - Ref comment below
That is totally possible to do but you need to decide what the business logic is that determines which organisation needs to be displayed here.
If you can explain exactly how your relationships are supposed to work it shouldn't be too difficult to show you how to apply your logic
UPDATE - How to get the primary organisation
This is simply a matter of setting up a new association on the Account model
has_one :primary_organization.
:class_name => 'Organization',
:conditions => ['primary = ?', true]
Then in your show action just write
#account.primary_organization.first #because anything use on a find other than the primary key will always return an array even if there is only one record.
You might also want to check that primary_organization is not empty?
Consider refactoring that has_one into a class method. May not be necessary depending on your needs
Read more here http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

As your relation is one-to-many, you have to use
#organization.first.name
it will show first organization.
as #organization is a array you have to collect all names and then show.

Related

Rails nested form creation

I have an app in which i want create nested form
my models:
class Abonent < ActiveRecord::Base
belongs_to :town
has_many :numbers, :dependent => :destroy
accepts_nested_attributes_for :numbers
end
class Number < ActiveRecord::Base
belongs_to :abonent
end
Abonents controller:
class AbonentsController < ApplicationController
def new
#abonent = Abonent.new
end
def create
#abonent = Abonent.new abonents_params
if #abonent.save
redirect_to :towns
else
render action: "new"
end
end
private
def abonents_params
params.require(:abonents).permit( :fullname, :work_position, :department, :email, :town_id, numbers_attributes: [ :phone ] )
end
end
And abonents view
<hr><br>
<%= form_for :abonents, url: abonents_path do |f| %>
<%= f.label :fullname %>:
<%= f.text_field :fullname %><br /> <br />
<%= f.label :work_position %>:
<%= f.text_field :work_position %><br /><br />
<%= f.label :department %>:
<%= f.text_field :department %><br /><br />
<%= f.label :email %>:
<%= f.text_field :email %><br /><br />
<%= f.label :town_id %>:
<%= f.select :town_id, Town.all.collect { |p| [ p.ru_name, p.id ] } %><br /><br />
<%= f.fields_for :numbers do |phones|%>
<%= phones.label :phone %>:
<%= phones.text_field :phone %><br /><br />
<% end %>
<%= f.submit %>
<% end %>
The problem is when i submit form, it creates abonent, but doesn't create number for this abonent.
I saw many different manuals and couldn't find the error in my code.
Please help.
Thank you.
UPD I added a repo on github for this problem.
You need to build the associated records
def new
#abonent = Abonent.new
#abonent.numbers.build
end

Routes in ruby with rails, html forms not working

I am new to ruby with rails,I generated a new Controller named users by using command:
rails generate controller users register index login
After that I opened register.html.erb and wrote following code:
<h1>Register New User</h1>
<p>
<%= form_for :user do |f| %>
<%= f.label:USERID %><%= f.text_field:userid %><br />
<%= f.label:PASSWORD %><%= f.text_field:password %><br />
<%= f.label:EMAIL %><%= f.text_field:email %><br />
<br />
<%= f.submit %>
<% end %>
</p>
Then in users_controller.rb I wrote following code in register:
class UsersController < ApplicationController
def index
end
def show
end
def login
end
def register
print "test"
end
def user_params
params.require(:user).permit(:userid,:password,:email)
end
end
And test is not being printed and get and post methods of the form are not working at all.
And params.require(:user).permit(:userid,:password,:email) is not working as well. I get error that :user is empty.
I get error that :user is empty.
form_for(path/to/your/controller/action) is a helper method to create HTML form elements with the url path to the POST or GET request. The helper knows if it should be a new record or an update record based on what you are asking to do in your controller action. So, basically, it's looking for the #user in the corresponding controller action when you write form_for #user in your view. As you don't have it currently, hence you ar getting this error.
See this for more information.
To solve your current problem, you have to define the #user in the controller's register action:
def register
#user = User.new(user_params)
end
Then, in your register.html.erb file's form, you can use that #user:
<h1>Register New User</h1>
<p>
<%= form_for #user do |f| %>
<%= f.label :USERID %>
<%= f.text_field :userid %><br />
<%= f.label :PASSWORD %>
<%= f.text_field :password %><br />
<%= f.label :EMAIL %>
<%= f.text_field :email %><br />
<br />
<%= f.submit %>
<% end %>
</p>

update record outside of namespaced admin [rails]

I have a named spaced admin in my app, where you can CRUD a client, this works great.
Outside of the admin within the app the #current_user has the opportunity to edit the client's address.
I am not sure how to access this and persist the new update to the database. this is what I have so far
products_controller.rb (where the partial is rendering from)
class ProductsController < ActionController::Base
layout "application"
def index
#products = Product.all
end
def show
#products = Product.all
#current_user = Client.find_by(id: session[:client])
end
end
_overlay_checkout.html.erb (this populates a form with the clients address from the db, and if its not updated they can change it.)
<%= simple_form_for([:admin, #current_user], :url => edit_admin_client_path) do |f| %>
<%= f.text_field :address %><br />
<%= f.text_field :address_line_2 %><br />
<%= f.select(:state, options_for_select(us_states, "CA")) %> <br />
<%= f.text_field :zipcode %><br />
<%= f.text_field :city %><br />
<%= f.submit %>
<% end %>
im unsure how I can update this record, ... without being in the admin section of the app, .. any help would be greatly appreciated.
One thing I've done in situations like this is to specify #submit_url as an instance variable in my controller action.
class ProductsController < ApplicationController
def show
#submit_url = client_path(#client)
end
end
You can can pass this variable to your form_for call like so:
<%= simple_form_for([:admin, #current_user], :url => #submit_path) do |f| %>
<%= f.text_field :address %><br />
<%= f.text_field :address_line_2 %><br />
<%= f.select(:state, options_for_select(us_states, "CA")) %> <br />
<%= f.text_field :zipcode %><br />
<%= f.text_field :city %><br />
<%= f.submit %>
<% end %>
If the #submit_url is not nil then the form action will be set to the value of the #submit_url otherwise it will get set to the resource based route that you specified. This means that in Admin Controller will not need to be changed at all. Just the alternate controller (in this case products_controller) where you want the submission of the form to go someplace other than the auto generated resourceful route.

rails form_for mongoid error

Hi i have a simple form for updating a user's account here is my controller
def edit
#users = User.find(params[:id])
end
here is my view
<%= form_for :user do |f| %>
<%= f.label :first_name %> <br />
<%= f.text_field :name ,:value => #users.name%><br />
<%= f.label :last_name %> <br />
<%= f.text_field :lname ,:value => #users.lname%><br />
<%= f.label :email %> <br />
<%= f.email_field :email ,:value => #users.email%><br />
<%= f.label :id %> <br />
<%= f.text_field :id ,:value => #users.id%><br />
<br />
<%= f.submit ({:confirm => "Are you sure?"}) %>
<% end %>
when i click submit i get the following mongoid error
Mongoid::Errors::InvalidFind in UsersController#edit
Problem:
Calling Document.find with nil is invalid.
Summary:
Document.find expects the parameters to be 1 or more ids, and will return a single document if 1 id is provided, otherwise an array of documents if multiple ids are provided.
Resolution:
Most likely this is caused by passing parameters directly through to the find, and the parameter either is not present or the key from which it is accessed is incorrect.
I'm fairly novice with rails and this is my first stab with mongoDB. Any input would help, Thank you.
Try to use this form
<%= form_for(#users) do |f| %>
...
...
<% end %>
The error comes because you are using :user that invalid find in your user controller

Double nested model forms

I am still having problems with nested forms. Here is my form code:
<%= form_for #account do |f| %>
<%= f.label :account_type %><br />
<%= f.text_field :account_type %><br />
<%= f.fields_for :organizations do |builder| %>
<%= builder.label :name %><br />
<%= builder.text_field :name %><br />
<%= builder.label :website %><br />
<%= builder.text_field :website %><br />
<%= f.fields_for :locations do |builder| %>
<%= builder.label :phone %><br />
<%= builder.text_field :phone %><br />
<%= builder.label :toll_free_phone %><br />
<%= builder.text_field :toll_free_phone %><br />
<%= builder.label :fax %><br />
<%= builder.text_field :fax %><br />
<% end %>
<% end %>
<%= f.submit "Add account" %>
<% end %>
The Account model:
class Account < ActiveRecord::Base
has_many :organizations
accepts_nested_attributes_for :organizations
end
The Organization model:
class Organization < ActiveRecord::Base
belongs_to :account
has_many :locations
accepts_nested_attributes_for :locations
end
And the Location model:
class Location < ActiveRecord::Base
belongs_to :organization
end
And lastly, the Accounts Controller:
class AccountsController < ApplicationController
def new
#account = Account.new
organization = #account.organizations.build
organization.locations.build
#header = "Create account"
end
def create
#account = Account.new(params[:account])
if #account.save
#handle success
else
render 'new'
end
end
end
Here is the error I am getting:
ActiveRecord::UnknownAttributeError in AccountsController#create
unknown attribute: locations
Rails.root: C:/Documents and Settings/Corey Quillen/My
Documents/rails_projects/shop_manager
Application Trace | Framework Trace | Full Trace
app/controllers/accounts_controller.rb:12:in `new'
app/controllers/accounts_controller.rb:12:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"xuZLSP+PSjdra3v51nIkJYZeXRM0X88iF135hPlp4sc=",
"account"=>{"account_type"=>"Company",
"organizations_attributes"=>{"0"=>{"name"=>"Atlas",
"website"=>"www.atlas.com"}},
"locations"=>{"phone"=>"555-555-5555",
"toll_free_phone"=>"800-555-5555",
"fax"=>"512-555-5555"}},
"commit"=>"Add account"}
Any help with this will be greatly appreciated. I have been looking at this now for a couple of hours.
You should use new builder in nested form for nested nested form :)) :
<%= form_for #account do |f| %>
<%= f.label :account_type %><br />
<%= f.text_field :account_type %><br />
<%= f.fields_for :organizations do |builder| %>
<%= builder.label :name %><br />
<%= builder.text_field :name %><br />
<%= builder.label :website %><br />
<%= builder.text_field :website %><br />
<%= builder.fields_for :locations do |lb| %>
<%= lb.label :phone %><br />
<%= lb.text_field :phone %><br />
<%= lb.label :toll_free_phone %><br />
<%= lb.text_field :toll_free_phone %><br />
<%= lb.label :fax %><br />
<%= lb.text_field :fax %><br />
<% end %>
<% end %>
<%= f.submit "Add account" %>
<% end %>
An even DRYer solution:
1) in your Gemfile, list nested_form as a dependency.
2) in your models do this:
class Account < ActiveRecord::Base
accepts_nested_attributes_for :organizations
end
class Organization < ActiveRecord::Base
accepts_nested_attributes_for :locations
end
3) create regular forms for Organization under ./app/view/organizations/
and for Location under./app/view/locations/`
4) in your Account form, do this: (it gets pretty short this way!)
<%= nested_form_for #account do |f| %>
<%= f.label :account_type %><br />
<%= f.text_field :account_type %><br />
<%= f.fields_for :organizations %>
<%= f.submit "Add account" %>
<% end %>
5) in your Organization form, do this: (also pretty short)
<%= nested_form_for #organization do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %><br />
<%= f.label :website %><br />
<%= f.text_field :website %><br />
<%= f.fields_for :locations %>
<%= f.submit "Add Organization" %>
<% end %>
Check these RailsCasts:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2

Resources