I have the following 3 models in my application:
class Submission < ActiveRecord::Base
has_many :linkedsubmissions
end
class Linkedsubmission < ActiveRecord::Base
belongs_to :submission
has_many :lnksubtypes
end
class Lnksubtype < ActiveRecord::Base
belongs_to :linkedsubmission
end
In the code below '#submission.linkedsubmissions.lnksubtypes' is incorrect.
#history = Audit.find(:all, :conditions => ["auditable_id IN (?)",#submission.linkedsubmissions.lnksubtypes.map{|b| b.LSU_ID} ])
I need to find all audits with 'auditable_id' in #submission.linkedsubmissions.lnksubtypes
You need to add the following has_many relationship to your Submission model.
class Submission < ActiveRecord::Base
has_many :linkedsubmissions
has_many :lnksubtypes, :through => :linkedsubmissions
end
Now, you'll be able to reformat your query like this
#history = Audit.find(:all, :conditions => ["auditable_id IN (?)", #submission.lnksubtypes.map(&:LSU_ID) ])
Audit.find(:all, :conditions => ["auditable_id IN (?)",#submission.linkedsubmissions.map{|b| b.lnksubtypes.map{&:LSU_OID) }.flatten ])
But there should be a better way to get those LSU_OID with sql only.
#history = Audit.where(:auditable_id => #submission.lnksubtypes.map(&:LSU_ID))
slightly shorter
Related
I modeling a three tables
Event, EventEventCategory and EventCategory
class Event < ActiveRecord::Base
has_many :event_event_categories
has_many :event_categories, :through => :event_event_categories
scope :live_event, ->{where(visible_status: 1)}
end
class EventEventCategory < ActiveRecord::Base
belongs_to :event
belongs_to :event_category
end
class EventCategory < ActiveRecord::Base
has_many :event_event_categories
has_many :events, :through => :event_event_categories
end
And I get a event using live_event scope.
#events = Event.live_event
And I wanna get a live_event 's category_lists
Now I get a Category list usgin below code
EventCategory.where("id in (?)", EventEventCategory.where("id in (?)", #events.pluck(:id).uniq))
or
EventCategory.where("id in (?)", #events.joins(:event_event_categories).pluck(:event_category_id).uniq)
is another command exist get a events category's list like a
Event.live_events.event_categories
EventCategory.joins(:events).where(events: { visible_status: 1 })
maybe this one can help
Say I have a few activerecord models in my rails 3.1 project that look like this:
class Component < ActiveRecord::Base
has_many :bugs
end
class Bug < ActiveRecord::Base
belongs_to :component
belongs_to :project
scope :open, where(:open => true)
scope :closed, where(:open => false)
end
class Project < ActiveRecord::Base
has_many :bugs
has_many :components_with_bugs, :through => :bugs, :conditions => ["bugs.open = ?", true]
end
In Short: I have a has_many through association (components_with_bugs) where I want to scope the "through" model. At present I'm doing this by duplicating the code for the scope.
Is there any way to define this has many through association (components_with_bugs) such that I can reuse the Bug.open scope on the through model, while still loading the components in a single database query? (I'm imagining something like :conditions => Bug.open)
Rails 4 answer
Given you have:
class Component < ActiveRecord::Base
has_many :bugs
end
class Bug < ActiveRecord::Base
belongs_to :component
belongs_to :project
scope :open, ->{ where( open: true) }
scope :closed, ->{ where( open: false) }
end
You have two possibilities:
class Project < ActiveRecord::Base
has_many :bugs
# you can use an explicitly named scope
has_many :components_with_bugs, -> { merge( Bug.open ) }, through: :bugs, source: 'component'
# or you can define an association extension method
has_many :components, through: :bugs do
def with_open_bugs
merge( Bug.open )
end
end
end
Calling projet.components_with_bugs or project.components.with_open_bugs will fire the same sql query:
SELECT "components".* FROM "components"
INNER JOIN "bugs" ON "components"."id" = "bugs"."component_id"
WHERE "bugs"."project_id" = ? AND "bugs"."open" = 't' [["project_id", 1]]
Which one is better to use depends on your application. But if you need to use many scopes on the same association, I guess association extensions could be clearer.
The real magic is done with merge which allows you to, as the name says, merge conditions of another ActiveRecord::Relation. In this case, it is responsible for adding AND "bugs"."open" = 't' in the sql query.
Apart from your scopes , write the default scope as:
default_scope where(:open => true) in your "through" model Bug.
class Bug < ActiveRecord::Base
belongs_to :component
belongs_to :project
default_scope where(:open => true)
scope :open, where(:open => true)
scope :closed, where(:open => false)
end
And in the Project model remove :conditions => ["bugs.open = ?", true]
class Project < ActiveRecord::Base
has_many :bugs
has_many :components_with_bugs, :through => :bugs
end
I think the above will work for you.
Try using the following.
has_many :components_with_bugs, :through => :bugs do
Bug.open
end
Can't you use something like this ?
has_many :components_with_bugs, :through => :bugs, :conditions => Bug.open.where_values
I haven't tested it, just proposing an path for investigation
The http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html specifies
:conditions Specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as authorized = 1.
Hence you can do it as:
class Project < ActiveRecord::Base
has_many :bugs
has_many :components_with_bugs, :through => :bugs do
def open
where("bugs.open = ?", true)
end
end
end
EDIT:
You can't specify another model's scope as a condition. In your case, they way you have it implemented is right. You can implement it another way as
has_many :components_with_bugs, :through => :bugs # in this case, no need to use the relation.
def open_bugs
self.bugs.openn # openn is the scope in bug. Don't use name 'open'. It's a private method of Array.
end
i need a little help with a AR query. This is how my models look like:
class User < AR:B
has_many :publications
end
class Publication < AR:B
belongs_to :user
belongs_to :category
end
class Category < AR:B
has_many :publications
end
Now let's say I want to iterate over all existing categories and either display the user's publications, or display something like "#{current_user.name} has no publications in this category".
class PublicationsController < AC:B
def index
#categories = Category.find(:all, :include => :publications, :conditions => { 'publications.user_id' => current_user })
end
end
This gives me all Categories the user actually has publications, but lacks the "empty" ones.
Any suggestions? :-)
This gives you all the Category objects:
#categories = Category.all
Then, if you declare has_many :through associations you can do something like the following:
#categories.each do |category|
if category.users.include?(current_user)
# User has publications
publications = category.publications.select { |pub| pub.user == current_user }
else
# User has no publications
end
end
(has-many-through declarations:
class User < AR:B
has_many :publications
has_many :categories, :through => :publication
end
class Publication < AR:B
belongs_to :user
belongs_to :category
end
class Category < AR:B
has_many :publications
has_many :users, :through => :publication
end
... warning: drycode)
There's probably an neater way to do this using named scopes though.
You might be able to just modify the find call:
#categories = Category.find(:all, :include => :publications, :conditions => [ 'publications.user_id=? OR publications.user_id IS NULL', current_user ])
Notice that we use the Array variant here rather than the Hash variant, since the example in the documentation implies this is the correct usage.
I have 2 models Widget and Feature which have a has many through association using WidgetFeature model.
class Widget < ActiveRecord::Base
has_many :widget_features
has_many :features, :through => :widget_features
end
class WidgetFeature < ActiveRecord::Base
belongs_to :feature
belongs_to :widget
attr_accessible :children_features, :widget_id, :feature_id
end
class WidgetFeature < ActiveRecord::Base
belongs_to :feature
belongs_to :widget
attr_accessible :children_features, :widget_id, :feature_id
end
I have a widget_id.
So i do Widget.find_by_id(widget_id)
Now i want to find all the features for this widget where widget_features.children_features IS NULL.
I dont know how to do this, help me out.
Try
#widget = Widget.find_by_id(widget_id)
#features = #widget.features.conditions("widget_features.children_features IS nil")
EDITED
Ref this
has_many :features, :through => :widget_features, :conditions=>["widget_features.children_features is nil"]
AND then
#widget = Widget.find_by_id(widget_id)
#features = #widget.features
Feature.all(:joins => :widget_features, :conditions => ["widget_id = ? and children_features is null", some_id])
I worked my way around named_scope and found an elegant solution. So, I am posting it here so that others stuck with the same problem can also get help.
My solution gives you a way to access any column of the join model in the has many through association.
Here's the solution for my problem above:
class Widget < ActiveRecord::Base
has_many :widget_features
has_many :features, :through => :widget_features
def leaf_features
widget_features.leaf_features.map{|widget_feature|widget_feature.feature}
end
end
class WidgetFeature < ActiveRecord::Base
named_scope :leaf_features, :conditions => 'children_features IS NULL'
belongs_to :feature
belongs_to :widget
attr_accessible :children_features, :widget_id, :feature_id
end
Now, Widget.find_by_id(widget_id).leaf_features
will give you only those features where
children_features column is NULL.
Say I have these models
class Project < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :project
belongs_to :user
end
class User < ActiveRecord::Base
has_many :comments
end
So that I can do
p = Project.find(1, :include => :comments)
p.comments.collect(&:user).collect(&:name) # this executes select for each user
How do I say I want to also include comment's user?
I believe :include => {:comments => :user} should work.