Rails: check presence of nested attribute - ruby-on-rails

If I have the following nested model relationships (all has_many):
Countries < Cities < Streets < Homes
In a show view, how can I check if a particular Country has any homes?
Edit:
Adding the suggested method of chaining with the map method (first try to map to streets). So far it's not restricting the records
<% #countries.each do |country| %>
<% if country.cities.map(&:streets).any? %>
....
<% end %>
<% end %>

You can call or #country.cities.map(&:streets).flatten.map(&:homes).present? or #country.cities.map(&:streets).map(&:homes).any?
<% if #country.cities.map(&:streets).flatten.map(&:homes).flatten.any? %>
Tro-lol-lo yo-lo-puki
<% end %>
Also you can wrap this long line into your model method:
class Country < ActiveRecord::Base
def any_homes?
cities.map(&:streets).flatten.map(&:homes).flatten.any?
end
end
Usage
<% if #country.any_homes? %>
Tro-lol-lo yo-lo-puki
<% end %>
And of course it looks like a good data structure for refactoring! It wants to be refactored!

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 :)

Displaying has_many, :through association records

I am working on an application a deep association. A Story belongs to a Planning Level, the Planning Level belongs to one or many Programs.
class Program < ActiveRecord::Base
has_and_belongs_to_many :planning_levels
has_many :stories, :through => :planning_levels
end
class PlanningLevelsPrograms < ActiveRecord::Base
end
class PlanningLevel < ActiveRecord::Base
has_and_belongs_to_many :programs
has_many :stories
end
class Story < ActiveRecord::Base
belongs_to :planning_level
end
Within the Program show page I'd like to display the Program, each Planning Level and aggregate Story count for each Planning Level.
I'm not sure how to access the Story model from the Program show page.
The following works great for displaying each Planning Level belonging to the Program.
<% #program.planning_levels.each do |p| %>
<p><%= p.name %></p>
<% end %>
...but I have no idea how to make the following work for each displayed Planning Level. How do I access the Story model from with the Program? Is there something needed in the Program controller that I'm missing. Thanks in advance!
#program.planning_level.stories.count(:id)
Each Planning Level:
<% #program.planning_levels.each do |planning_level| %>
<p><%= planning_level.name %></p>
# Aggregate Story count for each planning_level
<p><%= planning_level.stories.count %></p>
<% end %>
Aggregate Story count for #program (if you want):
#program.stories.count
Hope this can help you.
In your view, you can simply use the model associations by name to do this. Try this code as a starting point for your display needs:
<% #program.planning_levels.each do |planning_level| %>
<p><%= planning_level.name %> with <%= planning_level.stories.count %> stories</p>
<% planning_level.stories.each do |story| %>
<p><%= story.name %></p>
<% end %>
<% end %>
You can output any details that you choose for the stories loop. You can add styling to get the presentation that you need.
For instance, you might consider formatting this as a nested list, like so:
<% #program.planning_levels.each do |planning_level| %>
<ul>
<li>Planning Level: <%= planning_level.name %> with <%= planning_level.stories.count %> stories
<ul>
<% planning_level.stories.each do |story| %>
<li>Story: <%= story.name %></li>
<% end %>
</ul>
</li>
</ul>
<% end %>
Adding CSS class and id attributes would give you the ability to add styling to the elements to give your UI some flair.

Rails: show post when attributes is set to true

I am facing a weird bug and unfortunately I don't know how to investigate about it.
I am rendering certain pins on my homepage when the integer => pinoftheday is set to true. I am manually setting some pins to true.
For some pins its working well and they are appearing on the homepage, some others just don't. Btw, I am checking in my console and they are correctly set to true.
Here is a bit of code:
<% #pins.each do |pin| %>
<% if pin.pinoftheday %>
(...) some informations about the pin
<% end %>
<% end %>
Any ideas how I could check why some pins are not rendering? I am not writting any tests for now... I know this is stupid but I just did not learnt testing for rails.
Thank you.
EDIT: Yes, in my code it's a pin model. I wanted to used post to make it clearer. Figured it was not :) - Edited it to the correct model: pin.
Try the below code.
<% #postss.each do |post| %>
<% if post.pinoftheday %>
(...) some informations about the pin
<% end %>
<% end %>
Your problem is that you've defined a local variable in your block, and are referencing another:
<% #postss.each do |post| %>
<% if post.pinoftheday %>
...
<% end %>
<% end %>
--
You'd be better using a scope:
#app/models/post.rb
class Post < ActiveRecord::Base
scope :pin_of_the_day, -> { where pinoftheday: true }
end
You'll also do well to make your pinoftheday column boolean. If you're referencing 1 = true; 0 = false, Rails handles that with a tinyint in your db, calling true/false as boolean logic. Instead of referencing the integer as a number, you can call true etc.
The above will allow you to call:
#app/controllers/your_controller.rb
class YourController < ApplicationController
def index
#postss = Post.pin_of_the_day
end
end
This will remove the inefficient conditional logic (<% if ...):
<% #postss.each do |post| %>
...
<% end %>
If I understood your code then will below:
<% #postss.each do |pin| %>
<% if pin.pinoftheday.nil? %>
(...) some informations about the pin
<% else %>
(...) some informations about the pin
<% end %>
<% end %>
Hope will help you

Make a loop in a rails scope

Here is my structure:
Villa model with a belong_to association with a destination model (destination_id).
User model with a habtm association with destination model.
Today in my index view, I use :
<% current_user.destinations.each do |destination| %>
<% #villas.each do |villa| %>
<% if destination == villa.destination %>
<%= villa.name %>
<%end%>
<%end%>
<%end%>
It's not very clear, so can I make a kind of scope in my villa model to select Villas where destination_id == current_user.destinations ?
Thanks a lot
Why don't you list the children villas from the destination itself?
<% current_user.destinations.each do |destination| %>
<% destination.villas.each do |villa| %>
<%= villa.name %>
<%end%>
<%end%>
If you want to forgo this built-in functionality, or if you're scoping a query further from your #villas relation, here's how you do the scope as per these docs
class Villa < ActiveRecord::Base
# ...
scope :by_destinations, -> (destinations) { where(destination: destinations) }
# alternatively...
def self.by_destinations(destinations)
where(destination: destinations)
end
end
Then refer to it with
<% #villas.by_destinations(current_user.destinations) do |villa| %>
<%= villa.name %>
<%end%>

Rails 3 group_by associated model

I've been trying to group models in index by an associated model.
Here's what i have:
I have model location.rb
belongs_to :continent
which belongs to Continent.rb
has_many :locations
locations_controller.rb
def index
#locations = Location.find(:all)
end
and on my Index page
<% #locations.group_by(&:continent_id).each do |continent, locations| %>
<li><%= continent %></li>
<% locations.each do |location| %>
<%= location.name %>
<% end %>
<% end %>
I want to group locations by continent. This code above works, but i just need to show the name of the continent, now it shows only the id nr.
What's the best way to do it ?
I am newbie and I know this must be easy, but I'm a bit stuck.
Thanks.
First, it seems to me you're listing the continents, not the locations (to keep it restfull). So I would change that for the continents controller. In the continents controller:
def index
#continents = Continent.find(:all)
end
In continents/index.html.erb:
<% #continents.each do |continent| %>
<li><%= continent.name %></li>
<% continent.locations.each do |location| %>
<%= location.name %>
<% end %>
<% end %>

Resources