Rails 4 - Polymorphic Associations & instances - ruby-on-rails

I am making an app in Rails 4.
I have an address model, which is polymorphic.
My associations are:
profile.rb
has_many :addresses, as: :addressable
address.rb
belongs_to :addressable, :polymorphic => true
In my address.rb, I have a method for:
def country_name
self.country = ISO3166::Country[country]
country.translations[I18n.locale.to_s] || country.name
end
In my profile views folder, I have a partial to display a user's country, as:
<span class="profilesideinfo">
<% if #addresses.country_name.present? %>
<%= #addresses.country_name.titlecase %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
</span>
I have also tried:
<% if #profile.addresses.country_name.present? %>
<%= #profile.addresses.country_name.titlecase %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
And I have also tried (changing country_name (which is the method in my model) to country (which is the attribute in my address table))
Im getting stuck, because I can successfully create an address, but then that country name should show in the profile show partial. It doesn't. Instead, I get an error that says:
undefined method `country_name' for nil:NilClass
Is there something else that needs to happen for a reference to a polymorphic instance to show in the parent.
Can anyone see what needs to happen to get this to work?
I have tried making a scope in my profile model as:
Profile.joins(:addresses).where("addresses.profile_id = ?", profile_id)
I'm not sure this is adding any value. I'm not sure how to use it or whether it works, given that the address model doesn't have a foreign key for profile_id.
When I save this and try to reload the page, I get this error:
undefined local variable or method `profile_id' for #<Class:0x007fbacaec2d18>
Taking SurreyMagpie's suggestion below, I change the partial to:
<% if #profile.addresses.country_name.any? %>
<%= #profile.address.country_name.first.titlecase %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
I am checking if there are any addresses and then displaying the first country name.
When I try this, I get this error:
undefined method `country_name' for #<ActiveRecord::Associations::CollectionProxy []>

The polymorphic nature of the association is not responsible for your difficulties here.
When you define country_name as a method in your Address class, that is known as an instance method. As such, you are able to call it on a single Address object. So, if in the rails console you run Address.first.country_name you should receive a result for that specific instance of Address.
However, when you query a has_many association, in your case #profile.addresses, you get an ActiveRecord::Associations::CollectionProxy returned, even if there is only a single Address record. It is not exactly an array but has very similar behaviour.
The point is: you cannot call your instance method on the whole set at once. You need to iterate through the collection and call the method on each instance. For example:
<% if #profile.addresses.any? %>
<% #profile.addresses.each do |address| %>
<span class="profilecountry">
<%= address.country_name.titlecase %>
</span>
<% end %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
may be what you need - though how you choose to display multiple countries is up to you.

Related

How do I implement associations in searchkick

First, the example I read in the docs shows to declare the associated model as singular, :address, but if I do I get the error Association named 'address' was not found on User; If I change it to plural :addresses, then the next problem I have is the association doesn't work in views undefined method `country' for ...
Why am I declaring the association as plural and how can I make the association available in the view
User.rb:
class User < ActiveRecord::Base
searchkick word_middle: ['full_name', 'description', 'interests']
has_many :addresses
scope :search_import, -> { includes(:addresses) }
search.html.erb:
<% #users.each do |u| %>
<li>
<%= link_to "#{u.first_name} #{u.middle_name} #{u.last_name}", page_path(name: u.name) %>
<% #ua=u.addresses.where("current=?", true) %>
<% if #ua.country=="US" %>
<%= #ua.city %>, <%= #ua.state %> <%= ISO3166::Country.find_country_by_alpha2(#ua.country) %>
<% else %>
<%= #ua.city %>, <%= ISO3166::Country.find_country_by_alpha2(#ua.country) %>
<% end %>
</li>
<% end %>
</ul>
In controller, do this: #user = User.includes(:addresses).where(your_query) to make the association readily available in view.
And yes has_many associations are bound to be plural: "User has_one
:life" and "User has_many :passions"; does it make sense?
And finally your error: where returns an array because you queried: "bring me all records which fulfill this condition". find, on the other hand, will bring back 1 specific record as it expects a unique attribute or brings back first record that matches that attribute.
What you need to do:
You should either do this (if you are dead-sure that you will get 1
such record or you need only one of that type):
<% #ua=u.addresses.where("current=?", true).first %>
OR
If you need to go through all the resultant array then:
<% #ua=u.addresses.where("current=?", true) %>
<% #ua.each do |ua| %>
# Your code for each ua instead of #ua.
<% end %>
Happy Learning :)

getting message School:0x00559eba30b8b8 instead of displaying school name

I'am trying to display school name which is related to members, but I got the School:0x00559eba30b8b8, instead the name.
<% #members.each do |member| %>
<%= member.name %>
<%= member.email %>
<%= member.school %>
<% end %>
result : John john#john.com #School:0x00559eba30b8b8
update:
with school_id I get the id of the school, but still don't know how to get the name.
How can I get the name of the school?
Many thanks
Since school is not mandatory attribute, it can’t be just queried for the name, one should use try there:
<%= member.school.try :name %>
Assuming you have school_id in members table you need to print school.name instead of school
<% #members.each do |member| %>
<%= member.name %>
<%= member.email %>
<%= member.school.try(:name) %>
<% end %>
NOTE: member.school will return you an instance of School and you want to print just name.
Use
<%= member.school.try(:name) %>
Note:- Assuming your school has attribute 'name'
Also in your controller where you finding #members use 'includes', something like
#members = member.where().includes(:school)

ActiveRecord_Associations_CollectionProxy:0x0000000e490b98 in RoR

I'm creating a application using ruby on rails, but currently i'm suffering a problem like db relation, below my code:
Company
has_many :posts, :foreign_key => :company_id
Post
belongs_to :companies, :foreign_key => :company_id
controller
#post = current_user.companies.all
view
<% #post.each do |p| %>
<%= p.posts.post_title %>
<% end %>
Showing error above code.
If I debug like use <%= debug p.posts %> then showing all posts, which is under my companies but when I use <%= debug p.posts.post_title %> then showing ActiveRecord_Associations_CollectionProxy:0x0000000e490b98
Thanks
I think the problem here is that you are trying to call the method :post_title on p.posts, which is an ActiveRecord::Associations::CollectionProxy object.
In your example, p is a Company object, which has a method posts, which returns to you a CollectionProxy object that acts a lot like a list of posts. That list will not have a method post_title, but each element of that list will have a method post_title
So, instead of
<% #post.each do |p| %>
<%= p.posts.post_title %>
<% end %>
You will want something like:
<% #post.each do |company| %>
<% company.posts.each do |post| %>
<%= post.post_title %>
<% end %>
<% end %>
Two additional things to note:
1) The variable #post is inaccurately named. Inaccurate variable names will lead to confusion when trying to understand what is happening. current_user.companies.all returns a list of companies, and therefore, it should read:
#companies = current_user.companies.all
not
#post = current_user.companies.all
2) The actual error that is being shown to you likely says something like
Undefined Method 'post_title' for ActiveRecord_Associations_CollectionProxy:0x0000000e490b98
Not just
ActiveRecord_Associations_CollectionProxy:0x0000000e490b98
When debugging and asking for help, it's very important to note the entire message of the exception being raised.
Because companiy has_many :posts........ posts are objects you need a loop to show all posts e.g
p.posts.each do |post|

Scope of each on rails template

I'm new to rails and I'm trying to build a view that will list the parents and related children
Ex:
Passport has many Visas
I want to list information about the passport and the visas that the passport has.
So I have
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<% end %>
<% end %>
I'm getting the error
undefined method `visa_type' for #Passport:0x000000091b8b28
It looks like rails is trying to find the property visa_type for passport, instead of in visa. How does the scope work within each? Can I force it to access visa_type from visa?
I think you're looking for the fields_for form helper. This will allow you to create fields for the relevant visa attributes. Replace your code sample with the following, and you should be all set.
<% #passport_list.each do |passport| %>
# passportFields
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
You can also iterate over the list as follows:
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
<% end %>
For more information on fields_for, check out the link I added above, and to customize further for your use case, check out the "One-to-many" section.
IMO you should always handle the null case of an object.
Something like this if you use rails (present? is a Rails function)...
<% if #passport_list.present? %>
<% #passport_list.each do |passport| %>
passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<%end%>
<%end%>
<% else %>
<p>Nothing to see here</p>
<% end %>
However if your #passport_list is backed by an ActiveRecord Query, you can handle this in the model/helper/controller by returning the .none query on the model. Note that this differs from an empty array because it is an ActiveRecord Scope, so you can chain AR queries onto it
# scope on AR model
def self.awesomeville
where(country_of_origin: "awesomeville")
end
# method queried in controller
#passport_list = Passport.all
if #passport_list.present?
#passport_list
else
Passport.none
end
# additional filtering in view is now possible without fear of NoMethodError
#passport_list.awesomeville
Whereas a ruby Array would raise an error as it would respond to the Array methods.

Array of checkboxes in Rails

There is 'FoodType' model which are describes types of food in restaurants. I need to make view for creating a new restaurant, and I need to have list of checkboxes in order to allow user to setup types of food for each restaurant. I want to have something like this:
<% FoodType.all.each do |food_type| %>
...
<div class="row">
<%= f.check_box :food_types[0] %>
</div>
...
<% end %>
I want to have parameters like params[restaurant][food_types][0] = true in order to make some actions after creating. Please, tell me, how can I do it? Thanks in advance.
Presumably you have a join table which joins restaurants and food types? Let's say that you have one called restaurant_food_types (with a model RestaurantFoodType), which has restaurant_id and food_type_id?
You will then have this association in restaurants:
Restaurant < ActiveRecord::Base
has_many :restaurant_food_types
has_many :food_types, :through => :restaurant_food_types
This will give you the method .food_type_ids which you can call on a restaurant to set the joins. It's this method that you should hook into in your form: it expects an array of ids, so you need to set up an array-style parameter (one where the name ends in []) You may need to use check_box_tag rather than .check_box, to access an array-style parameter name: i would do this:
<% form_for #restaurant do |f| %>
<% FoodType.all.each do |food_type| %>
...
<div class="row">
<%= check_box_tag "restaurant[food_type_ids][]", food_type.id, #restaurant.food_type_ids.include?(food_type.id) %><%= food_type.name %>
</div>
...
<% end %>
<%= f.submit "Save" %>
<% end %>
Like i say i'm using a check_box_tag here but there might be a nicer way to hook into the food_type_ids method.

Resources