Using ActiveRecord, how can I do a LIKE query based on a property of an association? Specifically, I'm looking for something that works with polymorphic associations.
class Invoice < ActiveRecord::Base
has_one :private_note, class_name: '::Note', as: :noteable,
conditions: {label: 'private'}
has_one :public_note, class_name: '::Note', as: :noteable,
conditions: {label: 'public'}
end
class Note < ActiveRecord::Base
belongs_to :noteable, polymorphic: true
validates :content, :presence: true
end
I want to find invoices whose private_note has a content column containing the word "friendly".
Use #merge
This can be accomplished with the .merge method.
Invoice.joins(:private_note).merge(Note.where("content LIKE ?", '%friendly%'))
Related
I have a problem or dilemma after implementing polymorphic association following this: All the code is located here,
I have implemented this model:
Let's suppose that I also need the subscription to magazines. It will also be something similar to the other two
class Magazines < ApplicationRecord
has_many :subscriptions, as: :subscribable
end
class User < ApplicationRecord
has_many :subscriptions
has_many :podcasts, through: :subscriptions, source: :subscribable, source_type: 'Podcast'
has_many :newspapers, through: :subscriptions, source: :subscribable, source_type: 'Newspaper'
has_many :magazines, through: :subscriptions, source: :subscribable, source_type: 'Newspaper'
end
class Subscription < ApplicationRecord
belongs_to :subscribable, polymorphic: true
belongs_to :user
end
It works well, the problem now is ok I can handle like three types of subscription
MagazineSubscription, PodcastSubscription and NewspaperSubscription. The three have the same attributes and same behaviour, but belongs to different model. What happens If after doing that I need some kind of MTI or STI with the subscription classes. i.e. the MagazineSubscription have different behaviour and maybe other attributes. There is an easy way on this to accomplish this new requirement like creating a Subscription class that handles all that the polymorphic association and the other models:
class Subscription < ActiveRecord::Base
self.inheritance_column = :sti_subscription
belongs_to :subscribable, polymorphic: true
belongs_to :user
def _type=(sType)
sti_subscrition = sType.to_s.classify.constantize.base_class.to_s + "Subscription"
super(sType.to_s.classify.constantize.base_class.to_s)
end
end
class MagazineSubscription < Subscription
# new behaviour here
end
or I must follow something similar to this with the Subscription class handling two polymorphic relations, with the subscribable and his descendants
So my question is when I have used polymorphic association is an easy way to use that to set STI or MTI, or I need to make a new approach
We're having a problem with polymorphism & STI in Ruby
Our database has two tables: 'account' and 'list'. 'list' has columns 'account_id', 'type', 'description'.
Our classes look like so:
class Account < ActiveRecord::Base
has_many :lists
has_many :subscription_lists
has_many :email_lists
end
class List < ActiveRecord::Base
belongs_to :account
end
class SubscriptionList < List
end
class EmailList < List
end
Inside Account, methods email_lists and subscription_lists work exactly as expected. Our goal is we want to be able to call lists which will return an array of all lists. Currently, that doesn't work, nor does self.lists
Oddly, Account.find(self.id).lists DOES give us an array of all the lists associated.
What gives? How do we fix this?
You can use List.all which will return an ActiveRecord::Relation of all List objects, regardless of type.
Additionally, you can use #instance_variable.lists on any instance variable of Account
What's more, you could use a query on a class method to accomplish the job, like so, which will also return an ActiveRecord::Relation:
List.where('account_id = ?', id)
Lastly, your Account association with List should not include the children of List:
class Account < ActiveRecord::Base
has_many :lists, inverse_of: :account, dependent: :destroy
end
I have the following association code in my user.rb model file
class User < ActiveRecord::Base
has_many :sent_messages, class_name: 'ChatMessage', foreign_key: 'sender_id'
has_many :received_messages, class_name: 'ChatMessage', foreign_key: 'receiver_id'
end
I want a method in the ChatMessage model which should be triggered by the following
current_user.sent_messages
current_user.received_messages
The method should return the name of the association that was called.
Eg:
class ChatMessage < ActiveRecord::Base
after_find :get_association_name
def get_association_name
self.association_name // this should return sent_message or received_message depending on whether current_user.sent_messages or current_user.received_messages was called
end
end
Is there a way to get this association name in rails?
Any help is much appreciated. Thanks
I am not sure, exactly what you are looking for, but
CurrentUser.reflect_on_all_associations(:has_many)
will give an array of all has_many associations.
I haven't used AR associations extensions for cases like this, but you should be able to do:
has_many :sent_messages, class_name: 'ChatMessage', foreign_key: 'sender_id' do
def get_association_name; 'sent_messages'; end
# or, to make this more generic,
# def get_association_name; proxy_association.reflection.name.to_s; end
end
And the method should be accessible from your relation. If you were using Rails 4, you could extract the generic version out into a separate module to extend your associations more succinctly. See http://guides.rubyonrails.org/association_basics.html#association-extensions.
EDIT
Try:
has_many :sent_messages, class_name: 'ChatMessage', foreign_key: 'sender_id' do
def and_set_type
proxy_association.target.each do |msg|
msg.update_attribute(:type, 'sent')
end
scoped
end
end
And then access your sent_messages with current_user.sent_messages.and_set_type.
I have three models
class Boat < ActiveRecord::Base
belongs_to :captain
has_many :boat_classifications
has_many :classifications, through: :boat_classifications
end
class Classification < ActiveRecord::Base
has_many :boat_classifications
has_many :boats, through: :boat_classifications
end
class BoatClassification < ActiveRecord::Base
belongs_to :boat
belongs_to :classification
end
I'm trying to write a simple ActiveRecord query to find all the boats of type sailboat. Something like Boat.where(classifications: "Sailboat")
I think this could work:
Boat.joins(:classifications).where(classifications: { name: 'Sailboat' }) # name or whatever field contains Sailboat
Generates this query:
SELECT `boats`.* FROM `boats` INNER JOIN `boat_classifications` ON `boat_classifications`.`boat_id` = `boats`.`id` INNER JOIN `classifications` ON `classifications`.`id` = `boat_classifications`.`classification_id` WHERE `classification`.`name` = 'Sailboat'
I think you want something like this:
Boat.includes(:classifications).where(classifications: {id: Classification.sailboats})
For this to work, you also need a scope on Classification like this:
def self.sailboats
where(name: "Sailboat")
end
I'm trying to add multiple has_many relationships to my model:
class Program < ActiveRecord::Base
has_many :courses, :program_offers
belongs_to :university
attr_accessible :end_date, :name, :period, :start_date, :symbol, :year, :university_id, :description, :titles, :profile, :price
end
But I get:
hash expected error.
How can I reference two has many tables?
You can't do that because it is association method which takes only one association name as argument:
has_many(name, options = {}, &extension)
So specify each association in single line.
has_many :courses
has_many :program_offers
If you specify like that it considers that you are specifying some condition or block. See the API doc http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many