Display child values in parent view - ruby-on-rails

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.

Related

How to create multiple records with a nested form using check boxes

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!

simple_form rails 4, set automatic association

is a little project and I try to associate patient model with consultations. one patient has_many :consultations, in my form I have:
<%= f.association :patient %>
I pass the id parameter from the patient to the action 'new' in this way:
<%= link_to new_consultum_path(:id => #patient.id) %>
And in the view I have:
How can I make that the f.association field take the correspondent patient_id automatically?
How can I be sure that the patient_id is the current patient?
If I want to hide this field is that ok if I put
instead of
Is a better way to do this?
And why in the view shows me # patient:0x007f4e7c32cbd0 ?
thanks for your help.
And why in the view shows me # patient:0x007f4e7c32cbd0
This is a Patient object.
It means you need to call an attribute of this object - EG #patient.name.
--
f.association field take the correspondent patient_id automatically
This might help:
It looks like Organization model doesn't have any of these fields: [
:to_label, :name, :title, :to_s ] so SimpleForm can't detect a default
label and value methods for collection. I think you should pass it
manually.
#app/models/patient.rb
class Patient < ActiveRecord::Base
def to_label
"#{name}"
end
end
Apparently, you need to have either title, name or to_label methods in your model in order for f.association to populate the data.
-
How can I be sure that the patient_id is the current patient?
If you're having to verify this, it suggests inconsistencies with your code's structure. If you need the patient_id to be set as the current patient, surely you could set it in the controller:
#app/controllers/consultations_controller.rb
class ConultationsController < ApplicationController
def create
#consultation = Constultation.new
#consultation.patient = current_patient
#consultation.save
end
end
I can provide more context if required.
You want to associate consultations to patients using fields_for, which is similar to form_for, but does not build the form tags.
It you start with your patient object, you can iterate through the consultation associations binding it to form fields as you go.
it would look something like this
<%= form_for #patient do |patient_form| %>
<% patient_form.text_field :any_attribute_on_patient %>
<% #patient.consultations.each do |consultation| %>
<%= patient_form.fields_for consultation do |consultation_fields| %>
<% consultation_fields.text_field :any_attribute_on_consulatation %>
<% end %>
<% end %>
<% end %>
Sorry, the code may not be exactly right.
Check out the docs for field_for here
You will also have to set accepts_nested_attributes_for consultations on patient. When you set accepts_nested_forms_for, Rails will automatically update the associated consultations object to the patient and save any edits you have made. You DEFINITELY want to use accepts_nested_attributes_for most nested form handling of this type.

HABTM relationship with a text/hidden field for ids

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 %>

Rails 4 calling nested associations

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 -%>

How can I take advantage of my model associations in my view and controller in Ruby on Rails 3?

I am new to Rails and am trying to set up my Models and was wondering how Rails handles associations.
I have a Quest object which "belongs_to" or references via foreign keys a number of other objects, including User and Content:
quest.user_id
quest.a_different_name_id #this is a foreign key to a Content object
these are both foreign keys referencing a User object and Content object respectively.
Both User and Content "has_many" Quests.
I understand that this setup allows me to do things like:
u = User.create #saves to database
u.quests.build #creates new Quest object with user id set to u.id
Can I do something in the opposite direction like:
form_for #quest do |f|
f.text_field :a_user_attribute #an attribute of a User object
f.text_field :a_different_name_attribute #an attribute of a Content object
where the form has text fields for the attributes of the objects which a Quest object references through its foreign keys as opposed to having a form for the actual foreign keys, so that when in the controller I have:
#quest = Quest.new(params[:quest])
Is Rails smart enough to "reach through" the model-defined foreign key relationships and populate and then save the User and Content objects and appropriately set the foreign keys in #quest to reference the newly created objects?
Can it do this even though the foreign key for the Content object has a different name than content_id?
Hope this makes sense... let me know if I am being unclear.
You can do what you need with the Nested Attributes feature in Rails http://guides.rubyonrails.org/2_3_release_notes.html#nested-attributes
Check out the form helper for it here
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
Basically you would need to do the following:
class User < ActiveRecord::Base
has_many :quests
accepts_nested_attributes_for :quests
...
end
class Quest < ActiveRecord::Base
belongs_to :user
...
end
then in the form you do the following:
<%= form_for #user do |f| %>
UserAttrA : <%= f.text_field :a_user_attribute_a %>
UserAttrB: <%= f.text_field :a_user_attribute_b %>
<%= f.fields_for :quests do |qf| %>
QuestAttrA : <%= qf.text_field :a_quest_attribute_a %>
QuestAttrB: <%= qf.text_field :a_quest_attribute_b %>
<% end %>
UserAttrC : <%= f.text_field :a_user_attribute_c %>
UserAttrD: <%= f.text_field :a_user_attribute_d %>
<% end %>
And your controller would work just like you have above.
Note that you can display User inputs before and/or after Quest inputs. Basically you can make the form in the view look how you want. But the semantics on the server will be need to be consistent.

Resources