I'm pretty new to rails but started having this issue today which i haven't experienced before. Currently working on an application with a few nested associations. While i can create and add save these nested associations through the parent association i can't seem to call on elements from the associated model very well. I can see the information has been saved but when I call for it i get the name of the model not what is in the name column of the table.
brew.rb
class Brew < ActiveRecord::Base
has_many :fermentables
has_many :extras
has_many :hops
has_many :yeasts
accepts_nested_attributes_for :hops
end
hop.rb
class Hop < ActiveRecord::Base
belongs_to :brew
end
show.html.erb
<%= #brew.name %>
<%= #brew.story %>
<%= #brew.walkthrough %>
<%= #brew.hops.name%>
The show displays mostly everything just fine except when it comes to #brew.hops.name. It only displays Hop.
When I go into rails console I can see that the name had been saved. But only when I do something like.
t = Brew.last
t.hops.name
results only in the word "hops"
but if i just say
t.hops
i get
` SELECT "hops".* FROM "hops" WHERE "hops"."brew_id" = ? [["brew_id", 28]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Hop id: 6, name: "Warrior",
brew_id: 28, created_at: "2013-06-09 22:09:19", updated_at: "2013-06-09 22:09:19">]> `
Brew and hops are in relation one-to-many, so #brew.hops returns set of all hops belonging to #brew. So, if you want to display all associated hops names, you should do something like this:
<% #brew.hops.each do |hop| %>
<%= hop.name %><br />
<% end %>
t.hops returns an object representing the has_many association itself, not an individual Hop record, and calling the name method on that association object gives the name of the class of the associated model (the Hop class).
So I think you are wanting to iterate over the list of associated Hops and print each of their names:
<%- #brew.hops.each do |hop| -%>
Hop: <%= hop.name %>
<%- end -%>
Related
I have a Pizza model and Topping model with a PizzaTopping join table. Pizza has many toppings and topping belongs to pizza. I'm a novice with Rails.
My problem is trying to understand how to created a nested form that will add multiple records into my PizzaTopping join table. I also need the toppings to show up in check box form.
<div class="form-horizontal">
<%= form_for(#pizza) do |f| %>
Confusion #1:
To my understand this is to show a full model in check boxes, which works, but I'm confused on how the controller accepts this and creates the records in the join table of the toppings associated with the pizza. I want separate records(and not an attribute that is an array of topping ids):
PizzaTopping.create(id: 1, pizza_id: 1, topping_id: 1)
PizzaTopping.create(id: 2, pizza_id: 1, topping_id: 2)
PizzaTopping.create(id: 3, pizza_id: 1, topping_id: 3)
..
<div class="form-group">
<%= f.collection_check_boxes(:topping_ids, Topping.all, :id, :name) do |b| %>
<%= b.check_box %>
<%= b.label %>
<% end %>
</div>
or Confusion # 2:
This is a nested form but how do I get the toppings in check boxes from the Topping model and same as above, how do I code this in my controller to add records in the join table.
<div class="form-group">
<%= f.fields_for :toppings do |builder| %>
<%= builder.check_box %> // confused what I would even do next
<% end %>
</div>
...
<%= f.submit %>
<% end %>
</div>
First lets setup a indirect many to many relationship though the pizza_toppings table.
class Pizza < ActiveRecord::Base
has_many :pizza_toppings
has_many :toppings, through: :pizza_toppings
end
class Topping < ActiveRecord::Base
has_many :pizza_toppings
has_many :pizzas, through: :pizza_toppings
end
class PizzaTopping < ActiveRecord::Base
belongs_to :pizza
belongs_to :topping
end
What this accomplishes is that it lets you associate any number of pizzas with any number of toppings and ActiveRecord will handle joining for you:
#pizza = Pizza.find_by(name: 'Vesuvio')
#pizza.toppings
# => Topping( name: cheese ) ...
#pizza.toppings << Topping.find_by(name: 'Ham')
# inserts a record into the pizza_toppings table
# you can also do the inverse
#topping = Topping.find_by(name: 'Anchovies')
#topping.pizzas
# => Pizza( name: 'Napoli' )
To setup one to any or many to many relations via a checkbox you can use the collection_check_boxes helper.
<% form_for(#pizza) do |f| %>
<% f.collection_check_boxes(:topping_ids, Topping.all, :id, :name) %>
<% end %>
When you give a model a has_many association it gets a _ids setter which takes an array of ids and adds / removes associations, in this case ActiveRecord is also smart enough to know that it should setup the association through the join table when you use the through option.
The checkboxes generated by collection_check_boxes give you just that - an array in the params containing the ids of the selected toppings.
Note that you don't need to use fields_for here unless you intend to let users create pizzas and toppings on the same page. Also make sure you whitelist the topping_ids param.
def pizza_params
params.require(:pizza).permit(:name, topping_ids: [])
end
And now you got me all hungry.
First things first, if you are using a join table then you need to organise your relations differently, it makes no sense to use a join table with a belongs_to relationship, what you want to do is organise your relations so that a Pizza has_many :toppings, and a Topping has_many :pizzas and use the through: :pizza_toppings key.
Now onto your first confusion,
If you are using checkboxes the most you can hope to receive is the value of that checkbox, most likely the ids, this is then down to you to instantiate the records once you have the array of ids, perhaps something along the lines of selected_toppings = Topping.where(id: params[:topping_ids]) which will instantiate a collection of the toppings that were selected.
Also if you have your relations set up properly there is no need to explicitly create PizzaTopping records, this is a join table, and in my opinion I prefer to handle everything using the relations, something along the lines of pizza.toppings << selected_toppings should do the trick to set it all up.
Confusion two:
I dont think what you are looking for is a nested form, because you are not actually creating toppings, you just want a list of the toppings to relate to a pizza. Nested forms are when you want to create/edit and then write the attributes of a relation, your toppings are already preset, so just simply make checkboxes in the form normally with the values of your toppings ids.
Hope this helps!
I'm creating a has_and_belongs_to_many relationship with Rails. Each group has many participants and each participant can be part of many groups.
The relationship seems to be set up ok as I can use check boxes to add relationships using this in my form:
<%= collection_check_boxes(:group, :participant_ids, #participants, :id, :name) %>
However, I need to use a hidden field to submit these relationships (I use AJAX to fetch them in the view) with an array of ids (e.g. [1, 3]). I've tried using a text field like this but it doesn't save the data:
<%= f.text_field :participant_ids %>
When participant_ids saves using the checkboxes and I output it on the show view it's an array of ids but I can't seem to submit it in that format to start with.
Why can't I submit the participant_ids using a text/hidden field and is there a way around this?
For reference I've set up the join table and the models look like this:
class Group < ActiveRecord::Base
has_and_belongs_to_many :participants
end
class Participant < ActiveRecord::Base
has_and_belongs_to_many :groups
end
I also modified the group controller to work with strong parameters like this:
def group_params
params.require(:group).permit(:user_id, :purpose, :participant_ids => [])
end
I can post more code if necessary.
This answer worked for me. You will have to
<% #participants.each do |participant| %>
<% f.hidden_field 'participant_ids][', :value => participant.id %>
<% end %>
I have a one-to-many relationship in my rails application:
I have a User class that can have many Devices
I have a Device class that belongs to a User
My Models are designed like this:
class User < ActiveRecord::Base
has_many :devices
end
class Device < ActiveRecord::Base
belongs_to :user
end
Regarding views, when I want to display all Users and list their associated Devices I use this code:
<%= user.devices.each do |device| %>
<%= device.id %>
<% end %>
The output is: (only 1 device right now)
1 #<Device:0x101f45e50>
What I do not understand is why
#<Device:0x101f45e50>
is showing up after the id
replace equal sign
<% user.devices.each do |device| %>
<%= device.id %>
<% end %>
To give a litte more context so you know why this occurred, the = parses the output AND displays the result from the statement in the resulting HTML, where the - parses the line but does NOT display the result — since ruby passes a result at every new statement, you must put your = and - in the right spots.
Documentation is your friend (this is for HAML, but is still a good explanation)
I am really having trouble with what I would think is a relatively easy problem, and probably very easily rectified with something I am perhaps doing wrongly.
I have a Person model, and a Department model.
The relationships are a Person has_one :department, and Department belongs_to :person
In my view, when I'm looping to gather the person's attributes, I want to be able to access the Department name. I have the department_id as a foreign key in the Person table, so I can see the valid ID for each persons department, but how can I point this id to retrieve the department name.
<% #people.each do |p| %>
<%= p.name %>
<%= p.tel_num %>
<%= p.department_id %> <- i want this to somehow display the name of department
<% end %>
I have tried various things, p.department.name, p.department_id.name
NO LUCK!!
Very frustrating because I know its a very easy issue.
Any help much appreciated.
Update:
Sure heres my code:
Department model:
Class Department < ActiveRecord::Base
has_one :person
end
Person model:
Class Person < ActiveRecord::BAse
belongs_to :department
end
Show Person View:
<% #people.each do |p| %>
<p>Name: <%= "#{p.name}" %> </p>
<p>Start Date: <%= "#{p.start_date}" %> </p>
<p>Current Department: <%= "#{p.department_id}" %> <- displays relevant id
<% end %>
The person_department_id is being returned as 2, which would relate to "Accounts" in the department table, so thats fine.
When altering to your relations, and amending the view to: <%= p.department.name %> I still get the
undefined method `department' for #<Person:0x47f9040>
You've got relationship (hasone-belongsto) opposite way. Foreign key is supposed to be on 'belonging' side, department in your case.
So, you'll have to either update your database schema or switch has_one and belongs_to in your models.
You can read more on the subject here.
PS Also worth noting, it's very strange organization where every department consist of exactly one person.
edit On new data
You're inconsistent in your code. You used p.department_id in original post and p.person_department_id later.
Note, rails can't read foreign key name from your mind, so modelname_id is assumed by default. If you want something different, specify value explicitly.
Also, please do post updated code in your question rather than a new answer. Somebody might get confused.
To simplify things, I have 3 tables :
Person
has_many :abilities, through => :stats
Ability
has_many :people, through => :stats
Stats
belongs_to :people
belongs_to :abilities
Stats has an extra attribute called 'rating'.
What I'd like to do is make an edit person form that always lists all the abilities currently in the database, and lets me assign each one a rating.
For the life of me, I can't figure out how to do this. I managed to get it to work when creating a new user with something like this:
(from the people controller)
def new
#character = Character.new
#abilities = Ability.all
#abilities.each do |ability|
#person.stats.build(:ability_id => ability.id )
end
end
From the people form:
<% for #ability in #abilities do %>
<%= fields_for "person[stats_attributes]" do |t| %>
<div class="field">
<%= t.label #ability.name %>
<%= t.hidden_field :ability_id, :value => #ability.id, :index => nil %>
<%= t.text_field :rating, :index => nil %>
</div>
<% end %>
<% end %>
This successfully gives me a list of abilities with ratings boxes next to them, and lets me save them if i'm making a new user.
The problem is that if I then load up the edit form (using the same form partial), it doesn't bring back the ratings, and if I save, even with the exact same ratings, it creates duplicate entries in the stats table, instead of updating it.
I realize I'm a terrible programmer and I'm probably doing this the wrong way, but how do I get the edit form to recall the current ratings assigned to each ability for that user, and secondly how do i get it to update the rating instead of duplicating it if the combination of person and ability already exists?
Shouldn't that be
Character
has_many :stats
has_many :abilities, through => :stats
Ability
has_many :stats
has_many :characters, through => :stats
Stat
belongs_to :character
belongs_to :ability
?
Also, is it Person or Character? You refer variously to both. (I'm going to go with Character in my answer)
I think you've fallen foul of the "I'll try to make a simplified version of my schema in order to attempt to illustrate a problem but instead make things more complex and muddle the issue by screwing it up so it doesn't make sense" syndrome. Anyway, there's a couple of issues i can see:
1) first thing is that you're adding all the possible abilities to a character as soon as they're created. This is silly - they should start out with no abilities by default and then you create join table records (stats) for the ones they do have (by ticking checkboxes in the form).
2) A simple way to manipulate join records like this is to leverage the "ability_ids=" method that the has_many :abilities macro gives you - referred to as "collection_ids=" in the api http://railsbrain.com/api/rails-2.3.2/doc/index.html?a=M001885&name=has_many
In other words, if you say
#character.ability_ids = [1,12,30]
then that will make joins between that character and abilities 1, 12 and 30 and delete any other joins between that character and abilities not in the above list. Combine this with the fact that form field names ending in [] put their values into an array, and you can do the following:
#controller
def new
#character = Character.new
#abilities = Ability.all
end
#form
<% #abilities.each do |ability| %>
<div class="field">
<%= t.label #ability.name %>
<%= check_box_tag "character[ability_ids][]" %>
</div>
<% end %>
#subsequent controller (create action)
#character = Character.new(params[:character]) #totally standard code
Notice that there's no mention of stats here at all. We specify the associations we want between characters and abilities and let rails handle the joins.
Railscasts episodes 196 and 197 show how to edit several models in one form. Example shown there looks similar to what you're trying to do so it might help you out (same episodes on ascicasts: 196, 197).