rails advanced find - ruby-on-rails

I have three models:
class Address < ActiveRecord::Base
has_many :jobs
end
class Category < ActiveRecord::Base
has_many :jobs, :dependent => :destroy
end
class Job < ActiveRecord::Base
belongs_to :category
belongs_to :address
end
I'm trying to get all categories that the jobs has address_id != NULL
I'm almost there doing:
categories = Category.find(:all,:joins=>:jobs,:conditions=>'jobs.address_id is not null')
the problem is that i have a lot of repeated categories. I can solve it doing a:
categories.uniq!
but is not exactly the best solution.. Any idea?

Do you mean you have different categories with the same category name? If so you can try this:
categories = Category.find(:all,:joins=>:jobs,
:conditions=>'jobs.address_id is not null', :group => "category.name")
Note: If there are several categories with the same name you will get one of them. You have no control over the specific row returned to you.

Related

How to find not selected items in Many to Many Rails 4

I have the following Database structure.
class Category < ActiveRecord::Base
has_many :member_categories
has_many :members, :through => :member_categories
end
class Member < ActiveRecord::Base
has_many :member_categories
has_many :categories, :through => :member_categories
end
class MemberCategory < ActiveRecord::Base
self.table_name = "member_categories"
belongs_to :member
belongs_to :category
end
I can get any member categories as the following statement
Member.first.categories
there i find categories assigned to the member. I need to select the categories those are not assigned to the member. How can i write a scope to accomplish this.
Please advise, thanks in Advance.
This isn't a suitable job for a scope. Just write a method to find all categories with IDs not in the set of category IDs associated with the given member:
class Member
has_many :member_categories
has_many :categories, through: :member_categories
def not_categories
Category.where('id not in (?)', categories.pluck(:id))
end
end

Rails 3. Order by count of matches (many to many)

I have a many to many association between two models:
class User < ActiveRecord::Base
has_many :user_works
has_many :works, through: :user_works
end
class UserWork < ActiveRecord::Base
belongs_to :user
belongs_to :work
end
class Work < ActiveRecord::Base
has_many :user_works
has_many :users, through: :user_works
end
I have a filter by works, containing several works (ids).
My task is to filter users by works and order them by count of matches.
Thanks in advance.
I guess you need to group by works, and order by count
That's how to sort from less works to more:
User.joins(:works).group("user_works.user_id").order("COUNT(*)")
That's how to sort from more works to less:
User.joins(:works).group("user_works.user_id").order("COUNT(*) DESC")
Upd.
If you want to have some extra filtering just add where clause
User.joins(:works).where("user_works.work_id in #{filter_string}").group("user_works.user_id").order("COUNT(*) DESC")

Rails habtm joins

I have this relationship between categories, products & brands:
class Brand < ActiveRecord::Base
has_many :products
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
belongs_to :brand
end
How can I select all categories by specified brand with this relations?
I try this but get an error
b = Brand.find(1)
Category.joins(:products).where(:products => b.products)
You did the right thing with the join, just add a more complex where definition:
Category.joins(:products).where(:products => {:brand_id => 1})
Controversially HABTM's are rarely, if ever, a good design and IMO just about the only thing Rails got wrong.
Introduce an xref table to join products and categories and use has_many :through on both sides of the relationship so you end up with
class Brand < ActiveRecord::Base
has_many :products
has_many categories :through => products # This is now allowed in Rails 3.x and above
end
class Category < ActiveRecord::Base
belongs_to :product_category
has_many :products :through => product_category
end
class Product < ActiveRecord::Base
belongs_to :brand
belongs_to :product_category
has_many :categories :through => product_category
end
class ProductCategory < ActiveRecord::Base
has_many :products
has_many :categories
end
This gives you the best flexibility with the least amount of code re-factoring for you plus a much more intuitive path to get whatever data you need on either side of the relationship and will enable you to achieve the following
b = Brand.find(1)
b.categories.all
Update
The above is totally untested code and I have just corrected a glaringly stupid mistake I made. If you have any issues implementing this then come back

Rails - Query with has_many association

I am currently trying to create a custom method on a model, where the conditions used are those of a has_many association. The method I have so far is:
class Dealer < ActiveRecord::Base
has_many :purchases
def inventory
inventory = Vehicle.where(:purchases => self.purchases)
return inventory
end
end
This is not working, due to the fact that Vehicle has_many :purchases (thus there is no column "purchases" on the vehicle model). How can I use the vehicle.purchases array as a condition in this kind of query?
To complicate matters, the has_many is also polymorphic, so I can not simply use a .join(:purchases) element on the query, as there is no VehiclePurchase model.
EDIT: For clarity, the relevant parts of my purchase model and vehicle models are below:
class Purchase < ActiveRecord::Base
attr_accessible :dealer_id, :purchase_type_id
belongs_to :purchase_item_type, :polymorphic => true
end
class Vehicle < ActiveRecord::Base
has_many :purchases, :as => :purchase_item_type
end
class Dealer < ActiveRecord::Base
def inventory
Vehicle.where(:id => purchases.where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type_id))
end
end
Or:
def inventory
purchases.includes(:purchase_item_type).where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type)
end
I was able to do this using the :source and :source_type options on the Vehicle model, which allows polymorphic parents to be associated.

has_many :through association through two different associations

I have four model classes:
class Group < ActiveRecord::Base
has_many :projects
has_many :personal_blogs
end
class Project < ActiveRecord::Base
has_many :events, :as => :event_producer
end
class PersonalBlog < ActiveRecord::Base
has_many :events, :as => :event_producer
end
class Event < ActiveRecord::Base
belongs_to :event_producer, :polymorphic => true
end
I want to find all of the events for a particular group. I figure this is a has_many :through association, but how do I specify a has_many on Group that finds all events in the projects or personal_blogs of a group? I could, of course, specify two associations and concatenate the results, but then I have to re-sort, limit, condition, etc. in Ruby, which could potentially be a performance nightmare with many events. I'd like to do this within ActiveRecord to avoid such a nightmare.
You could define a method in the Group class like next:
class Group < ActiveRecord::Base
has_many :projects
has_many :personal_blogs
def events
Event.find(:all, :conditions => ['(type = ? AND event_producer_id IN (?)) OR (type = ? AND event_producer IN (?))', 'project', project_ids, 'personal_blog', personal_blog_ids])
end
end
If you don't like SQL like the previous one, it's always possible to use Single Table Inheritance. This solution depends on your classes attributes and behavior, but will allow you to use a "has_many through" association.
Why not just do:
class Group < ActiveRecord::Base
has_many :projects
has_many :personal_blogs
def all_events
projects.events + personal_blogs.events
end
end
If you need an association that you can preload you could specify a custom 'from' query that includes the group id with the event.
class Group < ActiveRecord::Base
has_many :projects
has_many :personal_blogs
has_many :events, -> {from(<<~SQL)}
(
SELECT DISTINCT e.*, g.id as group_id
FROM events e
LEFT JOIN projects p ON p.event_id = e.id
LEFT JOIN personal_blogs pb ON pb.event_id = e.id
INNER JOIN groups g ON g.id IN (p.group_id, pb.group_id)
) as events
SQL
end

Resources