Rectangle 27 1

turns out it's an old issue that wasn't solved yet

tested it with your code and it works.

ruby - Rails 4 - STI has_many :through with polymorphic association - ...

ruby ruby-on-rails-4 has-many-through polymorphic-associations sti
Rectangle 27 4

You're using Rails 4, so you can set a scope on your association. Your Supervisor class could look like:

class Supervisor < ActiveRecord::Base
  has_many :groups
  has_many :employees, lambda {
    where(type: 'Person::Employee')
  }, through: :groups, source: :owner, source_type: 'Person'
end

Then you can ask for a supervisor's employees like supervisor.employees, which generates a query like:

SELECT "people".* FROM "people" INNER JOIN "groups" ON "people"."id" = 
"groups"."owner_id" WHERE "people"."type" = 'Person::Employee' AND
"groups"."supervisor_id" = ? AND "groups"."owner_type" = 'Person' 
[["supervisor_id", 1]]

This lets you use the standard association helpers (e.g., build) and is slightly more straightforward than your edit 2.

Thanks, I didn't know has_many could take a Proc.

ruby on rails - "has_many :through" association through a polymorphic ...

ruby-on-rails ruby ruby-on-rails-4 model polymorphic-associations
Rectangle 27 13

An older question, but the issue in Rails 4 still remains. Another option is to dynamically create/overwrite the _type method with a concern. This would be useful if your app uses multiple polymorphic associations with STI and you want to keep the logic in one place.

This concern will grab all polymorphic associations and ensure that the record is always saved using the base class.

# models/concerns/single_table_polymorphic.rb
module SingleTablePolymorphic
  extend ActiveSupport::Concern

  included do
    self.reflect_on_all_associations.select{|a| a.options[:polymorphic]}.map(&:name).each do |name|
      define_method "#{name.to_s}_type=" do |class_name|
        super(class_name.constantize.base_class.name)
      end
    end
  end
end

Then just include it in your model:

class Car < ActiveRecord::Base
  belongs_to :borrowable, :polymorphic => true
  include SingleTablePolymorphic
end

It's important to add the concern directory to the load path: Adding a directory to the load path in Rails. Otherwise you will get an uninitialized constant error.

ruby on rails - Why polymorphic association doesn't work for STI if ty...

ruby-on-rails activerecord polymorphic-associations
Rectangle 27 2

Another option would be to use a polymorphic association, your classes could look like this:

class Source < ActiveRecord::Base
  belongs_to :content, polymorphic: true
end

class RSS < ActiveRecord::Base
  has_one :source, as: :content
  validates :source, :url, presence: true
end

When creating an instance you'd create the the source, then create and assign a concrete content instance, thus:

s = Source.create
s.content = RSS.create url: exmaple.com
accepts_nested_attributes_for

Your detect_type logic would sit either in a controller, or a service object. It could return the correct class for the content, e.g. return RSS if /(rss)$/ ~= self.url.

With this approach you could ask for Source.all includes: :content, and when you load the content for each Source instance, Rails' polymorphism will instanciate it to the correct type.

ruby - Rails STI class auto initialize - Stack Overflow

ruby-on-rails ruby ruby-on-rails-4 sti
Rectangle 27 13

Have you tried the simplest thing - adding :conditions to the has_many :throughs?

has_many :people, :through => :widget_groupings, :conditions => { :type => 'Person' }, :source => :grouper, :source_type => 'SentientBeing'
has_many :aliens, :through => :widget_groupings, :conditions => { :type => 'Alien' }, :source => :grouper, :source_type => 'SentientBeing'

JamesDS is correct that a join is needed - but it's not written out here, since the has_many :through association is already doing it.

Thanks a lot, this is what I was looking for.

ruby on rails - ActiveRecord, has_many :through, Polymorphic Associati...

ruby-on-rails ruby-on-rails-3
Rectangle 27 25

Good question. I had exactly the same problem using Rails 3.1. Looks like you can not do this, because it does not work. Probably it is an intended behavior. Apparently, using polymorphic associations in combination with Single Table Inheritance (STI) in Rails is a bit complicated.

The current Rails documentation for Rails 3.2 gives this advice for combining polymorphic associations and STI:

Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order for the associations to work as expected, ensure that you store the base model for the STI models in the type column of the polymorphic association.

In your case the base model would be "Staff", i.e. "borrowable_type" should be "Staff" for all items, not "Guard". It is possible to make the derived class appear as the base class by using "becomes" : guard.becomes(Staff). One could set the column "borrowable_type" directly to the base class "Staff", or as the Rails Documentation suggests, convert it automatically using

class Car < ActiveRecord::Base
  ..
  def borrowable_type=(sType)
     super(sType.to_s.classify.constantize.base_class.to_s)
  end

So that means you cannot associate a Car with a Guard and retrieve it with @guard.car, because the Car table will always have its 'borrowable_type' column set to 'Staff', and never to 'Guard'. And that means that polymorphic associations on STI models are completely useless.

It is possible, this answer worked for me. Mmmm... it is strange it doesn't work out of the box. I cant see why.

+1 for the link and description...

@dekeguard your statement regarding @guard.car is false. Using the solution provided, Rails transparently uses the STI base classname Staff as the target type and due to the fact that id's are always unique in an STI table it makes no difference whether the type is set to Guard or to Staff in the poly table the correct record will be fetched. Going from @car.guard will return the respective Guard too. So STI is useful with polymorphism because not only will the STI model work (with the provided solution) other models can still relate to the polymorphic model as well as desired.

ruby on rails - Why polymorphic association doesn't work for STI if ty...

ruby-on-rails activerecord polymorphic-associations
Rectangle 27 6

Rails 4.2

The problem is that Rails uses the base_class name of the STI relationship.

The reason for this has been documented in the other answers, but the gist is that the core team seem to feel that you should be able to reference the table rather than the class for a polymorphic STI association.

I disagree with this idea, but am not part of the Rails Core team, so don't have much input into resolving it.

There are two ways to fix it:

class Association < ActiveRecord::Base

  belongs_to :associatiable, polymorphic: true
  belongs_to :associated, polymorphic: true

  before_validation :set_type

  def set_type
    self.associated_type = associated.class.name
  end
end

This will change the {x}_type record before the creation of the data into the db. This works very well, and still retains the polymorphic nature of the association.

#app/config/initializers/sti_base.rb
require "active_record"
require "active_record_extension"
ActiveRecord::Base.store_base_sti_class = false

#lib/active_record_extension.rb
module ActiveRecordExtension #-> http://stackoverflow.com/questions/2328984/rails-extending-activerecordbase

  extend ActiveSupport::Concern

  included do
    class_attribute :store_base_sti_class
    self.store_base_sti_class = true
  end
end

# include the extension 
ActiveRecord::Base.send(:include, ActiveRecordExtension)

####

module AddPolymorphic
  extend ActiveSupport::Concern

  included do #-> http://stackoverflow.com/questions/28214874/overriding-methods-in-an-activesupportconcern-module-which-are-defined-by-a-cl
    define_method :replace_keys do |record=nil|
      super(record)
      owner[reflection.foreign_type] = ActiveRecord::Base.store_base_sti_class ? record.class.base_class.name : record.class.name
    end
  end
end

ActiveRecord::Associations::BelongsToPolymorphicAssociation.send(:include, AddPolymorphic)

A more systemic way to fix the issue is to edit the ActiveRecord core methods which govern it. I used references in this gem to find out which elements needed to be fixed / overridden.

This is untested and still needs extensions for some of the other parts of the ActiveRecord core methods, but seems to work for my local system.

ruby on rails - Why polymorphic association doesn't work for STI if ty...

ruby-on-rails activerecord polymorphic-associations
Rectangle 27 4

This should be the top voted answer. I installed the gem as instructed and voila, all workings as expected. Thanks!

ruby on rails - Why polymorphic association doesn't work for STI if ty...

ruby-on-rails activerecord polymorphic-associations
Rectangle 27 1

Take a look at the Polymorphic Associations section of ActiveRecord::Associations API. There is a little bit about using polymorphic associations in combination with single table inheritance. Following the second code example in that section I think this might be close to what you want

class Comment < ActiveRecord::Base
  belongs_to :commentable, :polymorphic => true, :counter_cache => true

  def commentable_type=(sType)
   super(sType.to_s.classify.constantize.base_class.to_s)
  end
end

class Post < ActiveRecord::Base
  has_many :comments, :as => :commentable, :dependent => :destroy, :order => 'created_at'
end

class NewsArticle < Post
end

ruby on rails - STI and polymorphs - Stack Overflow

ruby-on-rails activerecord polymorphic-associations single-table-inheritance
Rectangle 27 1

You are providing the association to comments on the Upload class. Photo, which is inheriting from Upload will have this association through inheritance. Since the comments method is available on both the Upload instance, and on the Photo instance, you can write the following method to retrieve the comments:

# app/models/upload.rb

def latest_comments(count=10)
  self.comments.order("created_at DESC").limit(count)
end

This will join to the comments table using the type "Upload" when working with an instance of Upload, and it will join using the type "Photo" when using working with instances of that class. Rails will automatically handle the join to the comments table using the class name when going through the comments association.

Thanks for the reply Ben, but my model specifies that only Photos, and not Uploads, are commentable. It greatly simplifies things if the superclass Upload is given the association has_many :comments, but I don't want to break my model by doing this. If I don't want to disrupt my model in that way, is what I want to achieve actually possible without a long chained query, I wonder?

ruby - Rails: Structuring a query involving a polymorphic association ...

ruby-on-rails ruby polymorphic-associations eager-loading single-table-inheritance
Rectangle 27 1

You are providing the association to comments on the Upload class. Photo, which is inheriting from Upload will have this association through inheritance. Since the comments method is available on both the Upload instance, and on the Photo instance, you can write the following method to retrieve the comments:

# app/models/upload.rb

def latest_comments(count=10)
  self.comments.order("created_at DESC").limit(count)
end

This will join to the comments table using the type "Upload" when working with an instance of Upload, and it will join using the type "Photo" when using working with instances of that class. Rails will automatically handle the join to the comments table using the class name when going through the comments association.

Thanks for the reply Ben, but my model specifies that only Photos, and not Uploads, are commentable. It greatly simplifies things if the superclass Upload is given the association has_many :comments, but I don't want to break my model by doing this. If I don't want to disrupt my model in that way, is what I want to achieve actually possible without a long chained query, I wonder?

ruby - Rails: Structuring a query involving a polymorphic association ...

ruby-on-rails ruby polymorphic-associations eager-loading single-table-inheritance
Rectangle 27 1

If you think the dual polymorphism is causing a problem, I suggest temporarily removing polymorphism from one of the hierarchies (and then the other) to see if you still have the issue. That will narrow down the scope of the problem.

Also, what do your schema defs look like? You might be missing a foreign key column.

Ok, I updated the post with the DB schema. I think I haven't missed anything, but you can look anyways.

Fixed! Had a missing admin_type inside the resellers table.

Ok, I did unvote (removing the green tick). Can you shortly explain why? Thanks.

@EmilPetkov Please accept again (put the green tick back). By "upvote" I mean click the UP arrow above the green tick to indicate that the answer was helpful.

ruby on rails - two STI hierarchies and polymorphic association(s) bet...

ruby-on-rails ruby activerecord
Rectangle 27 2

This is because Porshe is virtual model, it is not really exist in in database, it just has type field to know that it is Porshe. Maybe you should get rid of STI and use say type column to save Car model with type of Porshe and use scope to find porshes. I hope I helped you alittle.

Well this is the purpose of STI inheritance I guess, to use the same table for different classes to store.

ruby on rails - Polymorphic association foreign_type sets ancestor typ...

ruby-on-rails ruby activerecord polymorphic-associations single-table-inheritance
Rectangle 27 2

First, if you have different state (klass_id for KlassRating and type_id for TypeRating), you really don't have STI. You should have a table for Pilot class ratings and another table for Pilot type ratings. You might have a generic rating class which references a specific rating type with a polymorphic foreign key. Look up polymorphic in the belongs_to documentation.

Now for STI, you don't mention that you have a field named "type" in the "ratings" table. This is necessary so if you store a KlassRating or a TypeRating object instantiation, that it gets stored so when you retrieve it, it will by an object of the intended ruby class.

Having looked up the polymorphic foreign key I now see where I went wrong. I now have two separate tables for class ratings and type ratings and it is working flawlessly. Thanks!

Rails Single Table Inheritance (STI) in a form - Stack Overflow

ruby-on-rails single-table-inheritance
Rectangle 27 2

Baz's callbacks will only be triggered if you create it as a Baz object, i.e Baz.new(...).

However, you're not creating a Baz record, but rather a Bar record: Bar.new(type: 'Baz'). This will only trigger Bar's callbacks, even though that later on it will be treated as a Baz.

ruby - Rails callback not firing when building nested STI resource thr...

ruby-on-rails ruby callback sti
Rectangle 27 1

It's probably too late but you could also use has_and_belongs_to_many on User and Company and thus avoid STI altogether by using gems cancan and rolify. It allows you to define finely grained access rights (abilities).

I know that it seems more elegant having different classes instead of roles, but it is not viable long-term strategy, it can become messy when logic becomes complex.

Other then that, the rest seems pretty solid, hope that helps :)

ruby - Modelling an application in Rails - mixing STI and polymorphic ...

ruby-on-rails ruby ruby-on-rails-3.2 polymorphic-associations single-table-inheritance
Rectangle 27 1

Good question. I had exactly the same problem using Rails 3.1. Looks the problem is not solved yet. Apparently, using polymorphic associations in combination with Single Table Inheritance (STI) in Rails is a bit complicated.

The current Rails documentation for Rails 3.2 gives this advice for combining polymorphic associations and STI:

Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order for the associations to work as expected, ensure that you store the base model for the STI models in the type column of the polymorphic association.

In your case the base model would be "Post", i.e. "commentable_type" should be "Post" for all comments.

ruby on rails - STI and polymorphs - Stack Overflow

ruby-on-rails activerecord polymorphic-associations single-table-inheritance
Rectangle 27 1

To test the has_many within your PracticeManager model, you simply want:

RSpec.describe PracticeManager, type: :model do
  describe "Relationships" do
    it { should have_many(:providers) }
  end
end

If you want to test your Provider model, then you'd need the extra options:

RSpec.describe Provider, type: :model do
  it { should belong_to(:practice_manager).class_name('User').with_foreign_key(:user_id) }
end

ruby on rails - Testing STI Associations with Shoulda-Matchers & Facto...

ruby-on-rails rspec factory-bot shoulda sti
Rectangle 27 0

Assuming that you have a has_and_belongs_to_many join table with the name "products_sections", what you would need are these additional associations in your Prodcut model:

class Product < ActiveRecord::Base
 has_and_belongs_to_many :sections
 has_and_belongs_to_many :features, association_foreign_key: 'section_id', join_table: 'products_sections'
 has_and_belongs_to_many :standards, association_foreign_key: 'section_id', join_table: 'products_sections'
 has_and_belongs_to_many :options, association_foreign_key: 'section_id', join_table: 'products_sections'
end

Sign up for our newsletter and get our top new questions delivered to your inbox (see an example).

ruby on rails - HABTM association associated to single table inheritan...

ruby-on-rails ruby has-and-belongs-to-many sti
Rectangle 27 0

Have you tried the simplest thing - adding :conditions to the has_many :throughs?

has_many :people, :through => :widget_groupings, :conditions => { :type => 'Person' }, :source => :grouper, :source_type => 'SentientBeing'
has_many :aliens, :through => :widget_groupings, :conditions => { :type => 'Alien' }, :source => :grouper, :source_type => 'SentientBeing'

JamesDS is correct that a join is needed - but it's not written out here, since the has_many :through association is already doing it.

Thanks a lot, this is what I was looking for.

ruby on rails - ActiveRecord, has_many :through, Polymorphic Associati...

ruby-on-rails ruby-on-rails-3