Is it possible to eager load polymorphic nested associations? How can I include doctor_profile's for Recommendation's and patient_profile's for Post's?
I'm able to call Activity.includes(:trackable).last(10) but not sure how to include the associated models past there. I've tried belongs_to :recommendation, -> { includes :patient_profile, :doctor_profile} with no luck
class Activity
belongs_to :trackable, polymorphic: true
end
class Recommendation
has_many :activities, as: :trackable
belongs_to :doctor_profile
end
class Post
has_many :activities, as: :trackable
belongs_to :patient_profile
end
with respect referenced this SO answer and comments
for your problem you can managed with foreign_type field from polymorphic table to reference which model that use it
class Activity
belongs_to :trackable, polymorphic: true
# below is additional info
belongs_to :recommendation, foreign_type: 'Recommendation', foreign_key: 'trackable_id'
belongs_to :post, foreign_type: 'Post', foreign_key: 'trackable_id'
end
and you can call it
Activity.includes(recommendation: :doctor_profile).last(10)
Activity.includes(post: :patient_profile).last(10)
Activity.includes(recommendation: :doctor_profile) means
Activity will join recommendation with foreign_type and trackable_id
and then from recommendation will join doctor_profile with doctor_profile_id
The above answer works, but the use of foreign_type isn't actually supposed to do what the commenter intended.
https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
foreign_type is used to specify the name for the column which determines the class type for the relation.
I think the intended result here is to instead use class_name to specify which table the relation is referring to. If the relation has the same name as the table, then class_name can actually be inferred (which is why the provided answer works in the first place)
In order to get the above answer to work, specifying inverse_of for the belongs_to and adding for the has_many associations got everything to work. For example:
class Activity
belongs_to :trackable, polymorphic: true
# below is additional info
belongs_to :recommendation, foreign_type: 'Recommendation', foreign_key: 'trackable_id', inverse_of: :activities
belongs_to :post, foreign_type: 'Post', foreign_key: 'trackable_id', inverse_of: :activities
end
On the Post model:
has_many :activities, inverse_of: :post
On the Recommendation model:
has_many :activities, inverse_of: :recommendation
Related
I have 3 models as follows :
class User
has_many :event_series, inverse_of: :user
has_many :events, through: :event_series, inverse_of: :user
end
class EventSeries
belongs_to :user, inverse_of: :event_series
has_many :events, inverse_of: :event_series
end
class Event
belongs_to :event_series, inverse_of: :events
has_one :user, through: :event_series, inverse_of: :events
end
This is all fine.
Now I want to add a special event for each user called the 'showcase_event'.
class User
has_one :showcase_event, class_name: 'Event', inverse_of: :user
end
This isn't working because the Event model doesn't have the user directly, it's associated through EventSeries.
I'm getting an error during serialization:
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column events.user_id does not exist
I'm using fast jsonapi:
class PublicUserSerializer
include FastJsonapi::ObjectSerializer
...
has_one :showcase_event, record_type: :event, serializer: EventSerializer
...
end
It seems to me that the inverse relationship that I have between User, Event and EventSeries needs to work between User and showcase_event but I don't know how to specify that ONLY the inverse is through EventSeries
Apologies in advance for not having the best vocabulary to describe this problem.
Solved by my rubber duck.
As seen in the documentation :
The #belongs_to association is always used in the model that has the
foreign key.
So I changed my declaration of the showcase_event to this :
class User
belongs_to :showcase_event, class_name: 'Event', inverse_of: :user, optional: true
end
And problem solved
I have two models that both accept_nested_attributes_for each other. I know this is causing issues with rails_admin but can't seem to figure out the appropriate command to exclude nested attributes in my configuration. Ideally I would like to exclude nested attributes for all models so that this problem does not happen again.
Branden,
You need to inform the bi-direction association using inverse_of:
Ex:
class User < ActiveRecord::Base
belongs_to :company, :inverse_of => :users
accepts_nested_attributes_for :company
end
For both sides of association:
class Company < ActiveRecord::Base
has_many :users, inverse_of: :company
accepts_nested_attributes_for :users, :allow_destroy => true
end
More information in the docs: http://guides.rubyonrails.org/association_basics.html#bi-directional-associations
I'm trying to design a comment system allowing users to post on other users' pages, through comments.
A user will have a comment on his page, which is posted by another user called "commenter."
1) Is the following code legit/functional/decent design?
2) Is it OK to have a renamed "commenter" user, in conjunction with an un-renamed "user", or should all association names of user always be renamed semantically?
3) Are there better ways to implement this design intent (e.g. not doing a has_many through:)?
class User < ActiveRecord::Base
has_many :comments
has_many :users, through: :comments
has_many :commenters, through: :comments, class_name: 'User'
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commenter, class_name: 'User'
end
NOTE:
I wish to allow users to comment on users, but also on other models, (e.g. characters, celebrities). So I would think having the comments table be used in various has_many through associations is called for.
users has many commenters through comments
characters has many commenters through comments
celebrities has many commenters through comments
I believe your design is not going to work as it is - you are mixing has_many with has_many through. If I were you I would use an approach like this one:
class User < ActiveRecord::Base
has_many :owned_comments, class_name: 'Comments', foreign_key: 'owner_id'
has_many :posted_comments, class_name: 'Comments', foreign_key: 'commenter_id'
end
class Comment < ActiveRecord::Base
belongs_to :owner, class_name: 'User'
belongs_to :commenter, class_name: 'User'
end
have to tried acts_as_commentable gem it give lot of other options as well like public,private comment https://github.com/jackdempsey/acts_as_commentable
I implemented a similar functionality in mongoid and rails. The models were User, Friendship and Request. Its like User sends friend request to another user.
class User
include Mongoid::Document
include Mongoid::Timestamps
devise :invitable, :database_authenticatable, :registerable, :recoverable,
:rememberable, :trackable, :validatable, :confirmable
...
has_many :requests_from, class_name: "Request", inverse_of: :requested_by
has_many :requests_to, class_name: "Request", inverse_of: :requested_to
has_many :friendships, inverse_of: :owner
def friends
#retrive all the friendships and collect users have sent me a request or being sent a request.
fs = Friendship.any_of({:friend_id.in => [self.id]}, {:owner_id.in => [self.id]}).where(state: 'accepted')
User.in(id: fs.collect{|i| [i.friend_id, i.owner_id]}.flatten - [self.id])
end
end#User
class Friendship
include Mongoid::Document
include Mongoid::Timestamps
field :state, type: String, default: 'pending'
field :pending, type: Boolean, default: true
belongs_to :owner, class_name: 'User'
belongs_to :friend, class_name: "User"
validates :state, inclusion: { in: ["pending", "accepted", "rejected"]}
...
end#Friendship
class Request
include Mongoid::Document
include Mongoid::Timestamps
field :state, type: String, default: 'pending'
belongs_to :requested_by, class_name: 'User', inverse_of: :requests_from
belongs_to :requested_to, class_name: 'User', inverse_of: :requests_to
validates :state, inclusion: { in: ["pending", "accepted", "rejected"]}
...
end#Request
I hope this helps.
So in my current project I have an Article model that can have different kinds of Transactions. It has one main Transaction, but under certain circumstances it can have multiple sub-transactions.
Until now I set it up like this:
class Article < ActiveRecord::Base
has_one :transaction, inverse_of: :article
has_many :partial_transactions, through: :transaction, source_type: 'MultipleFixedPriceTransaction', source: 'PartialFixedPriceTransaction', inverse_of: :articles
end
class Transaction < ActiveRecord::Base
belongs_to :article, inverse_of: :transaction # Gets inherited to all kinds of Transaction subclasses
end
class MultipleFixedPriceTransaction < Transaction
has_many :children, class_name: 'PartialFixedPriceTransaction', foreign_key: 'parent_id', inverse_of: :parent
end
class PartialFixedPriceTransaction < Transaction
belongs_to :parent, class_name: 'MultipleFixedPriceTransaction', inverse_of: :children
belongs_to :article, inverse_of: :partial_transactions # Overwriting inheritance
end
Now with this set up I sometimes get errors like
ActiveRecord::Reflection::ThroughReflection#foreign_key delegated to
source_reflection.foreign_key, but source_reflection is nil:
#<ActiveRecord::Reflection::ThroughReflection:0x00000009bcc3f8 #macro=:has_many,
#name=:partial_transactions, #options={:through=>:transaction,
:source_type=>"MultipleFixedPriceTransaction",
:source=>"PartialFixedPriceTransaction", :inverse_of=>:articles, :extend=>[]},
#active_record=Article(id: integer ...
By the way, I experimented a lot with the source and source_type parameters and the ones there are just examples. I don't really know what to do with them.
So, how can I make this work? How is the association set up correctly?
Thank you.
I have a User and Address models. A user may have many addresses and one as default. I currently use this that works
# User.rb
belongs_to :default_address, class_name: "Address", foreign_key: :default_address_id
Now I made the Address belongs_to :addressable, polymorphic: true.
My question is how to tell this default_address self association to use the addressable instead of going directly to the Address class
Solved using has_one instead of belongs_to on User.rb
has_one :default_address, class_name: "Address", as: :addressable, dependent: :destroy
accepts_nested_attributes_for :default_address