I've got a database with an old schema that I'm going to be migrating data from. The table names and relationships are identical to the database. For some reason when I define the models for the old instance, they are acting as though they're the models of the new database.
from_db.rb
class FromDB < ActiveRecord::Base
self.abstract_class = true
establish_connection FROM_DB
end
from_clip.rb
class FromClip < FromDB
self.table_name = "clips"
belongs_to :clippable, polymorphic: true, counter_cache: true
belongs_to :video, class_name: "FromVideo"
end
clip.rb
class Clip < ActiveRecord::Base
belongs_to :clippable, polymorphic: true, counter_cache: true
belongs_to :video
end
console
FromClip.first.class.name
FromClip Load (0.2ms) SELECT `clips`.* FROM `clips` LIMIT 1
=> "Clip"
All the methods and associations available to FromClip are those in the Clip model rather than the FromClip model, but the instance of FromClip is from the correct database. Thanks for your help
So, it was related to STI. There are two models that inherit from Clip. If I use
self.inheritance_column = :_non_existing_column
in the FromClip model, it works as expected. I just have to point the clippable method at the right models and make sure I bring over the type column correctly.
def clippable
("From" + clippable_type).constantize.find_by_id(clippable_id)
end
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
I have a table of Industries and am keeping tracking of it's competitors which are also industries. This is through a mapping table industry_competitors which has industry_id and competitor_id. I want papertrail to track associations and dissociations of industry competitors.
class Industry < ApplicationRecord
has_many :industry_competitors, dependent: :destroy
has_many :competitors, through: :industry_competitors
end
class IndustryCompetitor < ApplicationRecord
has_paper_trail
belongs_to :industry
belongs_to :competitor, class_name: "Industry"
end
My controller code is as such.
competitors = ::Industry.where(id: params[:competitor_ids])
#industry.competitors = competitors
#industry.save
Every time the entire competitor list is passed. If I try to disassociate a few competitor (by not passing the ids to the controller) from the industry a 'Delete' query is fired.
DELETE FROM `industry_competitors` WHERE `industry_competitors`.`industry_id` = 4559 AND `industry_competitors`.`competitor_id` = 4564
I suspect because activerecord calls 'delete' and not 'destroy' this papertrail callbacks are not triggered hence the changes are not tracked.
If there a way to call delete explicitly (with minimal code changes). Or is there a way for papertrail to track delete?
Adding this patch can get it to work.
module HasManyThroughAssociationPatch
def delete_records(records, method)
method ||= :destroy
super
end
end
ActiveRecord::Associations::HasManyThroughAssociation.prepend(HasManyThroughAssociationPatch)
Credits: https://github.com/westonganger/paper_trail-association_tracking
So I think I need help with what I am doing with my asscoiations. I have two models (well many but for the purposes here). One is a Provider. Each provider can have a designation. Though the Designations is just a list it can appear in many different providers so it is not one to one. My models are as follows:
Provider.rb
class Provider < ActiveRecord::Base
has_and_belongs_to_many :groups
has_one :designation
has_one :specialty
end
Designation.rb
class Designation < ActiveRecord::Base
end
The error I get is this:
SQLite3::SQLException: no such column: designations.provider_id: SELECT "designations".* FROM "designations" WHERE "designations"."provider_id" = ? LIMIT 1
Which tells me my associations are off cause the designations should not have the provider_id, if anything the provider should have the designation_id.
Do I ditch the has_one and just put has_many in the Designation?
If I do that, I am new to rails, do I have to create a migration so the database is correctly updated?
Try using
models/provider.rb
belongs_to :designation
Then in
models/designation.rb
has_many :providers
It may feel a little strange but the belongs_to just lets you know which model the id column needs to go in. In this case the provider model, so you'll need:
rails g migration add_designation_id_to_provider designation_id:integer
I have the following:
class Publication < ActiveRecord::Base
belongs_to :project, :inverse_of => :publication
before_create :bind_project
private
def bind_project
self.create_project
end
end
class Project < ActiveRecord::Base
has_one :publication, :inverse_of => :project
end
According to this when creating a new Publication the publication_id attribute on the project model should be set by the create_project method.
Why it does not happen?
This is what I see on bind_project:
self.project_id is set correctly
self.project.publication_id is NULL
self.project.publication.id is set correctly
The database reflects this also: the projects.publication_id column is NULL.
Seems a bit strange, that you try to access the create_project method in a before_create callback. Typo? An after_create callback seems to be more appropriate.
Moreover: What for do you need the publication_id attribute on the has_one side of an association? There only needs to be one _id attribute on the belongs_to side.
Addendum to my first paragraph: As I see it, you are trying to use Rails magic on the associated object (the create_project method) before the actual base object is finished being created. Although this might work, this would be my first point to investigate.
Hello Everyone,
I have a polymorphic association currently in use with a few different models. Each model has it's own video file associated with it, so it uses a "videoable" polymorphic association. I recently found the need however, to create a new model that has 2 separate types of videos. I will let the code do the talking.
#current setup
class Video < ActiveRecord::Base
belongs_to :videoable, :polymorphic => true
end
class Project < ActiveRecord::Base
has_one :video, :as => videoable
end
# New model I am working on
class Assignment < ActiveRecord::Base
has_one :video_draft
has_one :video_final
end
Ideally the assignment model would have two special types of video objects while still using the polymorphic association. I have considered single table inheritance, but I am not sure that is the best approach here. What are my options? I do not want to create a video_draft model and a video_final model because in the end, they are just video attachments like everything else. The only difference is that they are specialized video attachments that need their own unique reference.
What you need to do is to tell ActiveRecord what model are you referring to when declaring :video_draft instead of :video like in Project model. This can be done by passing :class_name option to has_one
Keeping this in mind, this should work fine:
class Assignment < ActiveRecord::Base
has_one :video_draft, :as => :videoable, :class_name => "Video"
has_one :video_final, :as => :videoable, :class_name => "Video"
end
See rails guides at section 4.2.2.3 for more info about need for passing :class_name.