Multiple group_by - ruby-on-rails-3

I have three models :
dimension_mois
Admin::Style
Admin::Album
They are related like that :
**DimensionMois**
has_many :admin_styles, :class_name=>"Admin::Style"
**Admin::Style**
has_many :admin_albums, :class_name=>"Admin::Album"
**Admin::Album**
belongs_to :admin_style, :class_name=>"Admin::Style"
belongs_to :dimension_mois
The concept of the page is to show something like that :
I would like to show this for each month. Each month could have N styles. Each style could hve N albums.
I have no idea about the way to do that. I've tried with group_by, but the results are never good.
Any idea ? Thank you.

You might be overthinking the problem. I believe you just need to iterate over the objects and their associations, like so:
#dimension_moises = DimensionMois.includes(:admin_styles => :admin_albums)
// Using Haml syntax
%ul
- #dimension_moises.each do |dimension_mois|
%li
= dimension_mois.name
%ul
- dimension_mois.admin_styles.each do |admin_style|
%li
= admin_style.name
%ul
- admin_style.admin_albums.each do |admin_album|
%li= admin_album.title
That will give you a nested, hierarchical list of all the DimensionMois with the Admin::Styles and Admin::Albums for that object. You can use CSS, JS, whatever to style that list.

Related

activerecord - Time format

This has got to be extremely simple but I'm banging my head against the wall trying to find an answer. I want to find the last updated record using the instance method shown below.
class Subject < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
def get_last_assignment_date
#last_date = self.assignments.select("date_assigned").last
#last_day = #last_date.wday
end
Where my assignments model looks like this:
create_table "assignments", :force => true do |t|
t.date "date_assigned"
<snip>
But Rails returns the following error for get_last_assignment_date:
undefined method `wday' for #<Assignment date_assigned: "2012-08-30">
I need to convert the value returned by active record to a Time format that Ruby can handle but I can't figure out how to do it and it seems to be so easy that no one has even bothered to write how to do it. I would greatly appreciate it if someone could point me in the right direction.
This:
self.assignments.select("date_assigned").last
returns an Assigment object, not a Time object.
So, instead of:
#last_day = #last_date.wday
you have to do:
#last_day = #last_date.date_assigned.wday
You may be aware of this, but just in case: select("date_assigned").last doesn't give you the latest date. You have to use order:
self.assignments.order(:date_assigned).last
Of course if the most recently created object is also the one with the latest date_assigned then it doesn't matter.

Rails 3.1, internalization of values from a habtm relationship?

I got a Event model that HABTM Categories. The relationship works fine and I can insert/retrieve values from Categories with no problem.
My questions is, is there a way to interzationalize(I18n) the values of this categories.
Category Model
class Category < ActiveRecord::Base
has_and_belongs_to_many :events
end
Event Model
class Event < ActiveRecord::Base
....
has_and_belongs_to_many :categories
....
_form.html.haml (for events)
- Category.all.each do |category|
.field
= check_box_tag "category_ids[]", category.id, #event.category_ids.include?(category.id)
= category.name
I'm assuming the categories are pretty much fixed (otherwise you wouldn't really be able to do any i18n on them)
One solution would be to save the categories in the database as keys (with underscores) and for each key add the i18n to your locale files:
en.yml
categories:
some_category: "Some category text"
some_other_category: "Some other category text"
......
And if you do for example Category.all.map(&:name) will result in ["some_category", "some_other_category", ....]
And in your view:
- Category.all.each do |category|
.field
= check_box_tag "category_ids[]", category.id, #event.category_ids.include (category.id)
= I18n.t("categories.#{category.name}")
Note this is not a good solution if you're trying to do this dynamically (if that's the case, you're going to need to store the translations in the database, and this might help)

putting a condition on an includes

I have the following relationships:
Category has_many :posts
Post has_many :comments
Post has_many :commenters, :through => :comments
I have the following eager load, giving me posts, comments and commenters (note that I need all 3, and hence the includes as opposed to joins)
category.posts.includes(:comments, :commenters)
However, I'd like to limit comments (and if possible commenters) to only those created in the past two weeks while still returning the same set of posts. Initially I thought I could specify a condition on the includes:
category.posts.includes(:comments, :commenters).where("comments.created_at > ?", 2.weeks.ago)
But found that this returns only the posts that meet the condition. I'm thinking that I may need to do something like performing a subquery on comments and then performing a join. Is there an easy way to do this with AR of would I be better off doing this with sql?
Finally managed to figure this out from reading this page:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
I simply needed to create an association in my Post model like:
Post has_many :recent_comments, :class_name = 'Comment', :conditions => ["created_at > ?", 2.weeks.ago]
Then I could do the following to get the desired ActiveRecord::Association object:
category.posts.includes(:recent_comments => :commenters)
There was also a suggestion of doing this by using a scope on a model. However, I read somewhere (I think it was on SO) that scopes are on their way out and that ARel has taken their place so I decided to do this without scopes.
Try :
category.posts.all(:includes => {:comments =>:commenters}, :conditions => ["comments.created_at = ? AND commenters.created_at = ?", 2.weeks.ago, 2.weeks.ago]

Constructing a has-and-belongs-to-many query

I have a rails app (running on version 2.2.2) that has a model called Product. Product is in a has-and-belongs-to-many relationship with Feature. The problem is that I need have search functionality for the products. So I need to be able to search for products that have a similar name, and some other attributes. The tricky part is that the search must also return products that have the exact set of features indicated in the search form (this is represented by a bunch of checkboxes). The following code works, but it strikes me as rather inefficient:
#products = Product.find(:all, :conditions=>["home=? AND name LIKE ? AND made_by LIKE ? AND supplier LIKE ? AND ins LIKE ?",hme,'%'+opts[0]+'%','%'+opts[1]+'%','%'+opts[3]+'%','%'+opts[4]+'%'])
#see if any of these products have the correct features
if !params[:feature_ids].nil?
f = params[:feature_ids].collect{|i| i.to_i}
#products.delete_if {|x| x.feature_ids!=f}
end
I'm sorry that my grasp of rails/sql is so weak, but does anyone have any suggestions about how to improve the above code? Thanks so much!
First, i would recommend you to manually write a FeatureProduct model (and not use the default 'has_and_belongs_to_many')
EG
class FeatureProduct
belongs_to :feature
belongs_to :product
end
class Product
has_many :feature_products
has_many :features, :through => :feature_products
end
class Feature
has_many :feature_products
has_many :products, :through => :feature_products
end
For the search: You may find the gem SearchLogic to be exactly what you need. It has support for 'LIKE' conditions (it means that you can write in a more 'Rails way' your query). It also has support for performing a search with conditions on a related model (on your Feature model, to be more precise).
The solution would be something like:
search = Product.search
search.name_like = opt[0]
search.made_by_like = opt[1]
...
search.feature_products_id_equals = your_feature_ids
..
#product_list = search.all
There is also an excellent screencast explaining the use of this gem.
Good luck :)

Help with Rails find_by queries

Say if #news_writers is an array of records. I then want to use #news_writers to find all news items that are written by all the news writers contained in #news_writers.
So I want something like this (but this is syntactically incorrect):
#news = News.find_all_by_role_id(#news_writers.id)
Note that
class Role < ActiveRecord::Base
has_many :news
end
and
class News < ActiveRecord::Base
belongs_to :role
end
Like ennen, I'm unsure what relationships your models are supposed to have. But in general, you can find all models with a column value from a given set like this:
News.all(:conditions => {:role_id => #news_writers.map(&:id)})
This will create a SQL query with a where condition like:
WHERE role_id IN (1, 10, 13, ...)
where the integers are the ids of the #news_writers.
I'm not sure if I understand you - #news_writers is a collection of Role models? If that assumption is correct, your association appears to be backwards - if these represent authors of news items, shouldn't News belong_to Role (being the author)?
At any rate, I would assume the most direct approach would be to use an iterator over #news_writers, calling on the association for each news_writer (like news_writer.news) in turn and pushing it into a separate variable.
Edit: Daniel Lucraft's suggestion is a much more elegant solution than the above.