Giter Club home page Giter Club logo

active_record-acts_as's Introduction

Development moved

Active development of this project has moved to the fork of manuelmeurer. Please report issues and open PRs over there!

ActiveRecord::ActsAs

This is a refactor of acts_as_relation

Simulates multiple-table-inheritance (MTI) for ActiveRecord models. By default, ActiveRecord only supports single-table inheritance (STI). MTI gives you the benefits of STI but without having to place dozens of empty fields into a single table.

Take a traditional e-commerce application for example: A product has common attributes (name, price, image ...), while each type of product has its own attributes: for example a pen has color, a book has author and publisher and so on. With multiple-table-inheritance you can have a products table with common columns and a separate table for each product type, i.e. a pens table with color column.

Requirements

  • Ruby >= 2.2
  • ActiveSupport >= 4.2
  • ActiveRecord >= 4.2

Installation

Add this line to your application's Gemfile:

gem 'active_record-acts_as'

And then execute:

$ bundle

Or install it yourself as:

$ gem install active_record-acts_as

Usage

Back to example above, all you have to do is to mark Product as actable and all product type models as acts_as :product:

class Product < ActiveRecord::Base
  actable
  belongs_to :store

  validates_presence_of :name, :price

  def info
    "#{name} $#{price}"
  end
end

class Pen < ActiveRecord::Base
  acts_as :product
end

class Book < ActiveRecord::Base
  # In case you don't wish to validate
  # this model against Product
  acts_as :product, validates_actable: false
end

class Store < ActiveRecord::Base
  has_many :products
end

and add foreign key and type columns to products table as in a polymorphic relation. You may prefer using a migration:

change_table :products do |t|
  t.integer :actable_id
  t.string  :actable_type
end

or use shortcut actable

change_table :products do |t|
  t.actable
end

Make sure that column names do not match on parent and subclass tables, that will make SQL statements ambiguous and invalid! Specially DO NOT use timestamps on subclasses, if you need them define them on parent table and they will be touched after submodel updates (You can use the option touch: false to skip this behaviour).

Now Pen and Book acts as Product, i.e. they inherit Products attributes, methods and validations. Now you can do things like these:

Pen.create name: 'Penie!', price: 0.8, color: 'red'
  # => #<Pen id: 1, color: "red">
Pen.where price: 0.8
  # => [#<Pen id: 1, color: "red">]
pen = Pen.where(name: 'new pen', color: 'black').first_or_initialize
  # => #<Pen id: nil, color: "black">
pen.name
  # => "new pen"
Product.where price: 0.8
  # => [#<Product id: 1, name: "Penie!", price: 0.8, store_id: nil, actable_id: 1, actable_type: "Pen">]
pen = Pen.new
pen.valid?
  # => false
pen.errors.full_messages
  # => ["Name can't be blank", "Price can't be blank", "Color can't be blank"]
Pen.first.info
  # => "Penie! $0.8"

On the other hand you can always access a specific object from its parent by calling specific method on it:

Product.first.specific
  # => #<Pen ...>

If you have to come back to the parent object from the specific, the acting_as returns the parent element:

Pen.first.acting_as
  # => #<Product ...>

In has_many case you can use subclasses:

store = Store.create
store.products << Pen.create
store.products.first
  # => #<Product: ...>

You can give a name to all methods in :as option:

class Product < ActiveRecord::Base
  actable as: :producible
end

class Pen < ActiveRecord::Base
  acts_as :product, as: :producible
end

change_table :products do |t|
  t.actable as: :producible
end

acts_as support all has_one options, where defaults are there: as: :actable, dependent: :destroy, validate: false, autosave: true

Make sure you know what you are doing when overwriting validate or autosave options.

You can pass scope to acts_as as in has_one:

acts_as :person, -> { includes(:friends) }

actable support all belongs_to options, where defaults are these: polymorphic: true, dependent: :destroy, autosave: true

Make sure you know what you are doing when overwriting polymorphic option.

Migrating from acts_as_relation

Replace acts_as_superclass in models with actable and if you where using :as_relation_superclass option on create_table remove it and use t.actable on column definitions.

RSpec custom matchers

To use this library custom RSpec matchers, you must require the rspec/acts_as_matchers file.

Examples:

require "active_record/acts_as/matchers"

RSpec.describe "Pen acts like a Product" do
  it { is_expected.to act_as(:product) }
  it { is_expected.to act_as(Product) }

  it { expect(Person).to act_as(:product) }
  it { expect(Person).to act_as(Product) }
end

RSpec.describe "Product is actable" do
  it { expect(Product).to be_actable }
end

Contributing

  1. Fork it ( https://github.com/hzamani/active_record-acts_as/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Test changes don't break anything (rspec)
  4. Add specs for your new feature
  5. Commit your changes (git commit -am 'Add some feature')
  6. Push to the branch (git push origin my-new-feature)
  7. Create a new Pull Request

active_record-acts_as's People

Contributors

allenwq avatar crissofresh avatar felipeclopes avatar hzamani avatar lowjoel avatar manuelmeurer avatar mikem avatar mintuhouse avatar nicklandgrebe avatar nuclearpidgeon avatar ricardogzz avatar sophiedeziel avatar tiagoamaro avatar tombowo avatar zeeshan-siddhu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

active_record-acts_as's Issues

Child object does not sets the corrent _type on query

class Trail < ActiveRecord::Base
  belongs_to :trailable, polymorphic: true
end

class Event < ActiveRecord::Base
  actable

  has_many :trails, as: :trailable, dependent: :destroy

  accepts_nested_attributes_for :trails, allow_destroy: true
end

class Exam < ActiveRecord::Base
  acts_as :event
end

Trail.last.trailable.class.to_s
# "Exam"

Trail.last.trailable.trails.to_sql
# "SELECT \"trails\".* FROM \"trails\" WHERE \"trails\".\"trailable_id\" = 7 AND \"trails\".\"trailable_type\" = 'Event'"

As you can see, if the has_many :trails stay on parent class, it gets the trailable_type as Event, not Exam. There is some way to detect from where the has_many was called to set this type?

I have a has_one that works fine:

class Event < ActiveRecord::Base
  has_one :address, as: :addressable, dependent: :destroy

  accepts_nested_attributes_for :address, allow_destroy: true
end

class Address < ActiveRecord::Base
  belongs_to :addressable, polymorphic: true
end

Address.last.addressable.class.to_s
# "Event"

Address.last.addressable.address

# [2016-04-30T15:45:29] DEBUG ActiveRecord::Base :   Address Load (1.1ms)  SELECT  "addresses".* FROM "addresses"  ORDER BY "addresses"."id" DESC LIMIT 1
#[2016-04-30T15:45:29] DEBUG ActiveRecord::Base :   Event Load (0.4ms)  SELECT  "events".* FROM "events" WHERE "events"."id" = $1 LIMIT 1  [["id", 7]]
#[2016-04-30T15:45:29] DEBUG ActiveRecord::Base :   Address Load (0.4ms)  SELECT  "addresses".* FROM "addresses" WHERE "addresses"."addressable_id" = $1 AND "addresses"."addressable_type" = $2 LIMIT 1  [["addressable_id", 7], ["addressable_type", "Event"]]

Thank you.

Custom matchers for RSpec?

Hey @hzamani,

first of all, thank you very much for this gem. It already helped me a lot on past projects, and it's helping me again :)

On a current project, I noticed that I wanted to do a quick check on classes and instances of those classes to see if they were acting as/actables of a certain class or symbol, so I dig up your specs and saw that you have some nice boolean methods (#acting_as? + .acting_as? + .actable?) to verify that. Do you think it's interesting adding some custom matchers to the library to help people out writing specs?

Example:

# Sample rails_helper.rb

require 'rspec/acts_as_matchers'

# acts_as_matchers.rb

RSpec::Matchers.define :acts_as do |actable|
  match { |actor| actor.acting_as?(actable) }
end

RSpec::Matchers.define :be_actable do
  match { |instance| instance.class.actable? }
end

And then on specs, people would have available the following interfaces:

it { is_expected.to acts_as(:account) }
it { expect(Person).to acts_as(:account) }

it { is_expected.to acts_as(Account) }
it { expect(Person).to acts_as(Account) }

it { expect(described_class).to be_actable }

What do you think? :)

If you like the idea, I can open a PR with those changes right away. If not, I'll just close the issue.

update_all problem

I use active_record-acts_as. Did everything as described in the example. But now I want to make update_all and it does not work. Tried to use joins, but the query that is generated is of course wrong. I want to change all Products whose pens.color = 'red'. What am I doing wrong?

models:

class Pen < ActiveRecord::Base
    acts_as :product
end

class Product < ActiveRecord::Base
  actable
end

problem place:

Pen.joins(:product).where("pens.color = 'red'").update_all("products.price = 1")

sql generated:

UPDATE "pens" 
SET products.price = 1 
WHERE "pens"."id" IN 
(
    SELECT "pens"."id" 
    FROM "pens" 
    INNER JOIN "products" ON "products"."actable_id" = "pens"."id" AND "products"."actable_type" = 'Pen' 
    WHERE (pens.color = 'red')
)

Of course, in the query you can see that it is impossible to make set products when update pens. But how to fix it?

How to change to the correct query:

    UPDATE products as p
    set price = 1
    from pens
    WHERE pens."id" = p.actable_id and pens.color = 'red' and p.actable_type = 'Pen'

?

Parent class doesn't respect before_save filter of Child class

Suppose we have a Parent class and his Child class, let's say Attachment and Image respectively. If i put a before_save in Image, let's say

class Image
   act_as :attachment
   before_save :check_something
end

the check_something method won't be respected by Attachment, and any param that were in Attachment model and that were changed before executing image.save, will be saved anyway, whether it doesn't pass the check_something filter.

Validations of parent attributes on the child model.

Here is a very simplistic scenario to demonstrate my query.

I have two models, Attachment and Specification.

Attachment is made up of name:string, actable_id:integer and actable_type:string.
Specification is made up of draft:boolean.

class Attachment < ActiveRecord::Base
  actable
end

class Specification < ActiveRecord::Base 
  acts_as :attachment
end

I would like to validate name on the Specification model, instead of Attachment.

If I add the following:

class Specification < ActiveRecord::Base 
  acts_as :attachment
  validates :name, presence: true
end

And in the console:

> s = Specification.new
=> #<Specification id: nil, draft: nil, created_at: nil, updated_at: nil>
> s.name = "Nick"
=> "Nick"
> s.valid?
=> true

It validates.

If I try something a tiny bit more complex:

class Specification < ActiveRecord::Base
  acts_as :attachment
  validates :name, presence: true, uniqueness: { case_sensitive: false }
end

And do the same as before in the console:

> s.valid?

NoMethodError: undefined method `limit' for nil:NilClass
<trace snipped>

Trace: http://pastebin.com/C6PHZ5YD

It falls over.

Is this expected? Why does presence work, but not uniqueness?

The reason I am trying this is because my child models can have different validation implementations for the name column. name is also generic and so I was hoping I'd be able to give name an alias on each model to make the error messages more meaningful.

Sorry if this is a stupid question.

Convert subclass

@hzamani
Any recommendations on a short solution to convert one subclass into another?

For example: A Pen decides to become a Pencil

ArgumentError: wrong number of arguments (1 for 0)

In a project where worked fine the old gem (acts_as_relation), now we try to migrate to the new gem, but the problem is: heritage doesn't working.
The scene is the following: there are an AdminUser superclass and some others classes inherit from her, one of they is the Student class. So:

SuperAdmin model:

# in app/models/admin_user.rb
class AdminUser < ActiveRecord::Base
 validates_presence_of :name
 actable
end

Student model:

# in app/models/student.rb
class Student < ActiveRecord::Base
 acts_as :admin_user
end

SuperAdmin migration:

# in db/migrate/20140605111811_devise_create_admin_users.rb
class DeviseCreateAdminUsers < ActiveRecord::Migration
def change
 create_table(:admin_users) do |t|
  t.string :name, null: false
  t.actable
 end
end

Then go to terminal, run rails c and this happen when try to create a student:

irb(main):015:0> Student.create!(name: 'Student')
ArgumentError: wrong number of arguments (1 for 0)

The same error happen with the other models.

Some idea?.

Thanks in advance. ๐Ÿ‘

How to remove SELECT expressions in query

The gem adds the SELECT expressions like

"jobs"."id" AS t0_r0, "jobs"."job_description" AS t0_r1, .......

They cause error when using COUNT and GROUP BY functions in Postgres:

PG::GroupingError: ERROR: column "jobs.id" must appear in the GROUP BY clause or be used in an aggregate function

How can I remove them from the query?

P.S.

The rails code is:

states = Job.joins(listing: :location).select('count(locations.state) as count, locations.state').group('locations.state')

Using has_many belongs_to

I'm trying to setup a relation between a Company, and the Media that is associated with the Company, and I'm having trouble finding how to store the parent id on the join table (and not each individual child class in the join table)

Right now, I have

class Company < ActiveRecord::Base
   has_many :company_media
   has_many :media, through: :company_media
end
class Media < ActiveRecord::Base
   actable
   has_many :company_media
   has_many :companies, through: :company_media
end
class CompanyMedia < ActiveRecord::Base
   belongs_to :company
   belongs_to :media
end
class Photo < ActiveRecord::Base
   acts_as :media
end
class Video < ActiveRecord::Base
   acts_as :media
end

screenshot 2014-08-13 14 45 30

What I really want:

class Photo < ActiveRecord::Base
   acts_as :media
   has_many :company_media
   has_many :companies, through: :company_media
end
class Company < ActiveRecord::Base
   has_many :company_media
   has_many :photos, through: :company_media
   has_many :videos, through: :company_media
end

Essentially, I need the ability to say, company.photos.create and have it create a new Photo (with info in the Media and Photo tables), but store the Photo's media.id in the CompanyMedia table.

Has anyone made this happen successfully yet?

Multi level inheritance fails

Hello,
Here is the problem :
InternalPerson inherits Person inherits Contact
It fails associating correctly the 3.
Rails 4.1.8. Idem with 4.1.2

Migrations :
class CreateContact < ActiveRecord::Migration
  def change
    create_table :contacts do |t|
      t.actable

      t.string   :old_id, limit: 9
      t.boolean  :internal, null: false, default: false
      t.datetime :deleted_at

      t.timestamps
    end
    add_index :contacts, :old_id
  end
end

class CreatePerson < ActiveRecord::Migration
  def change
    create_table :people do |t|
      t.actable

      t.string :first_name, limit: 50
      t.string :last_name, null: false, limit: 50
      t.string :gender, limit: 1
      t.string :title, limit: 30
    end
    add_index :people, :last_name
  end
end

class CreateInternalPerson < ActiveRecord::Migration
  def change
    create_table :internal_people do |t|
      t.boolean :active_account, null: false
      t.string  :username, limit: 20
      t.string  :initials, limit: 3
      t.integer :seniority
      t.date    :welcome_date
      t.date    :last_med_visit
      t.date    :birthday, null: false
      t.date    :deceased_date, default: nil
      t.integer :marital_status_id
    end
    add_index :internal_people, :username
    add_index :internal_people, :initials
  end
end
Models :
class Contact < ActiveRecord::Base
  actable
end

class Person < ActiveRecord::Base
  actable
  acts_as :contact
end

class InternalPerson < ActiveRecord::Base
  acts_as :person
end
Test :
describe 'Internal Person' do

  it 'should create an internal person who is also a person and a contact' do
    ::Rails.logger.warn "Contacts : " + Contact.all.inspect
    ::Rails.logger.warn "Personnes : " + Person.all.inspect
    ::Rails.logger.warn "PersonnesInternes : " + InternalPerson.all.inspect
    expected = InternalPerson.create(first_name: 'Patrick', last_name: 'Vanhuyse', gender: 'H', title: 'Doctor',
                                     internal: true, old_id: '54', active_account: true, birthday: Date.today())
    ::Rails.logger.warn "Contacts : " + Contact.all.inspect
    ::Rails.logger.warn "Personnes : " + Person.all.inspect
    ::Rails.logger.warn "PersonnesInternes : " + InternalPerson.all.inspect

    p = Person.where(actable_id: expected.id).first
    c = Contact.where(actable_id: p.id).first

    expect(c.old_id).to eq(expected.old_id)
    expect(c.internal).to eq(expected.internal)
    expect(c.deleted_at).to eq(expected.deleted_at)
    expect { c.first_name }.to raise_error

    expect(p.first_name).to eq(expected.first_name)
    expect(p.last_name).to eq(expected.last_name)
    expect(p.gender).to eq(expected.gender)
    expect(p.title).to eq(expected.title)
    expect { p.active_account }.to raise_error

    expect(p.specific).to eq(expected)
    expect(c.specific).to eq(p)
  end
end

It fails on the last expect. c.specific is nil !
As you can see in the log, actable_type in contacts table is "InternalPerson". I think it should be "Person" to work, because when I launch all the tests I have, sometimes it works (surely depending of the order of the tests) and when it works, actable_type in contacts table is "Person".
Extract of the logs :

Contacts : #<ActiveRecord::Relation [#<Contact id: 262, actable_id: 193, actable_type: "InternalPerson", old_id: "54", internal: true, deleted_at: nil, created_at: "2014-11-28 09:59:31", updated_at: "2014-11-28 09:59:31">]>
Personnes : #<ActiveRecord::Relation [#<Person id: 193, actable_id: 124, actable_type: "InternalPerson", first_name: "Patrick", last_name: "Vanhuyse", gender: "H", title: "Doctor">]>
PersonnesInternes : #<ActiveRecord::Relation [#<InternalPerson id: 124, active_account: true, username: nil, initials: nil, seniority: nil, welcome_date: nil, last_med_visit: nil, birthday: "2014-11-28", deceased_date: nil, marital_status_id: nil>]>

I have looked at your code but it's far beyond my knowledge of Rails !

Can you please correct this issue ?
Thanks in advance.

Column name collisions in queries

Can't do a simple search against columns with the same name on both the actable and acting_as models. Could be more, but by default this will always include the created_at and updated_at fields.

irb(main):038:0* ActingAsModel.where("created_at > ?", time)
ActiveRecord::StatementInvalid: PG::AmbiguousColumn: ERROR:  column reference "created_at" is ambiguous
LINE 1: ..." AND "actable_model"."actable_type" = $1 WHERE (created_at...

The current workaround is that you have to search against the actable model and add the actable_type for the model you are actually searching.

ActableModel.where("created_at > ?", time).where(:actable_type => "ActingAsModel")

"Where" changes behavior

Hello there. Thanks for this gem! It's saved me lots of time. Please forgive me if this is a duplicate issue; I searched the existing issues and couldn't find something like this.

Normally when I have a product that belongs_to a store, I can search for products in a store like this:

@some_store = Store.find(5)
# ... some code
@products = Product.where(store: @some_store)

It seems like in this case, if you have a Pen that acts as a Product, then this won't work:

@pens = Pen.where(store: @some_store)

it will complain about an undefined column, products.store. So instead I'm doing this:

@pens = Pen.where(store_id: @some_store.id)

It's not a big deal, but it's not what I expected and took me a couple minutes to realize that your gem changes this behavior. What do you think?

Saving a acts_as record does not callback .touch on actable relation

If I have a model Product.rb with related associations like Brand.rb, I want to make sure Brand gets updated when Product gets updated. To do this, I'm using touch: true on the Product > Brand association. If I have Pen.rb that acts_as Product, and Pen gets saved, Product does not update Brand.

Code examples:

class Brand < ActiveRecord::Base
    has_many :products
end
class Product < ActiveRecord::Base
    actable
    belongs_to :brand, touch: true
end
class Pen < ActiveRecord::Base
    acts_as :product
end

Support Rails / ActiveRecord 5.0

Hey @hzamani wanted to see if there are any plans to upgrade to Rails 5

Bundler could not find compatible versions for gem "activerecord":
  In Gemfile:
    active_record-acts_as was resolved to 1.0.0, which depends on
      activerecord (~> 4.1.2)

    rails (< 5.1, >= 5.0.0.beta1) was resolved to 5.0.0.beta1, which depends on
      activerecord (= 5.0.0.beta1)

Specific association to acts_as models

Please correct me or suggest,

My concern is how to get a specific collection from has_many in Test::Owner models rather than generic?

When specifying

# adding to super_class.rb
belongs_to :ownerable, polymorphic: true

# change in owner.rb
has_many :sub_classes_a, as: :ownerable, class_name: 'Test::SubClassA'

and trying to get specific collection through has_many by invoking owner.sub_classes_a, Rails will automatically include the column test_sub_classes_as.ownerable_id in select query which is only possible in test_super_classes table giving an exception such column not found in table sub_classes_as.

With the following definition

# super_class.rb
class Test::SuperClass < ActiveRecord::Base
  belongs_to :ownerable, polymorphic: true
  actable as: :superclassable
end

# super class migration
create_table :test_super_classes do |t|
  t.references :ownerable, polymorphic: true
  t.actable as: :superclassable
  t.timestamps
end

# sub_class_a.rb
class Test::SubClassA < ActiveRecord::Base
  acts_as :super_class, as: :superclassable, class_name: 'Test::SuperClass'
end

# sub_class_b.rb
class Test::SubClassB < ActiveRecord::Base
  acts_as :super_class, as: :superclassable, class_name: 'Test::SuperClass'
end

# owner.rb, has_many actables
class Test::Owner < ActiveRecord::Base
  has_many :sub_classes_a, as: :ownerable, class_name: 'Test::SuperClassA'
end

# special_owner.rb, has_many actables, STI from Test::Owner
class Test::SpecialOwner < Owner
  has_many :sub_classes_b, as: :ownerable, class_name: 'Test::SuperClassB'
end

I am able to do Test::Owner.new(sub_classes_a: [Test::SubClassA.new]).save to save a specific object in the format

// table: test_super_classes (generic)
id: xx
ownerable_id: xx
ownerable_type: Test::Owner
superclassable_id: xx
superclassable_type: Test::SubClassA
...     

However, in my design I have to have has_many with specific class_name: 'Test::SubClassA' to enforce only these objects to be stored and referenced from the model. Moreover, SubClassA and SubClassB have to have a reference back to the owner

Thanks!

is_a? Confuses association consistency

AR checks that when assigning a variable to a relation (has_many/has_one) that the type of the variable assigned is consistent with the association. ActsAs overrides is_a?, which confuses this check. Anything that acts as the base type would be added, which could potentially give the wrong ID (since the ancestor ID and subclass ID are different)

I'm not sure what's a good fix for this, just sounding it out.

New release

Hey @hzamani. Looks like a couple of issues have been fixed. Will it be possible to get a new release?
Thanks

Custom column names

Is there a way I can define the names of the columns (actable_id, actable_type), to whatever names I like? I have a legacy multiple table inheritance database, and am unable to change the column names. Is there a way I can change the columns to 'some_id_name' and 'a_different_type_name', instead of actable_id and actable_type?

Also, I can't declare as: on the actable and acts_as, since they have different leading names.

"Can't Cast Hash to Date" when trying .update

It seems that I can't update date fields in the parent class:

if @contract.update(contract_params) ...

gets me

*TypeError in ContractsController#update_contract *
can't cast Hash to date

StackTrace:

activerecord (4.2.4) lib/active_record/connection_adapters/abstract/quoting.rb:34:in `rescue in type_cast'
activerecord (4.2.4) lib/active_record/connection_adapters/abstract/quoting.rb:23:in `type_cast'
activerecord (4.2.4) lib/active_record/connection_adapters/sqlite3_adapter.rb:290:in `block in exec_query'
activerecord (4.2.4) lib/active_record/connection_adapters/sqlite3_adapter.rb:289:in `map'
activerecord (4.2.4) lib/active_record/connection_adapters/sqlite3_adapter.rb:289:in `exec_query'
activerecord (4.2.4) lib/active_record/connection_adapters/abstract/database_statements.rb:76:in `exec_insert'
activerecord (4.2.4) lib/active_record/connection_adapters/abstract/database_statements.rb:108:in `insert'
activerecord (4.2.4) lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `insert'
activerecord (4.2.4) lib/active_record/relation.rb:64:in `insert'
activerecord (4.2.4) lib/active_record/persistence.rb:524:in `_create_record'
...

Things work fine if I

  • use the same code but only change things for the parent element itsself
  • don't try to update the date (e.g. by removing it from permitted parameters)

Any ideas?

unknown attribute 'actable_id' while creating child class

Hey there,

I have the following base class:

class IcAction < ActiveRecord::Base
actable
self.table_name = 'powerpet_ic_actions'

belongs_to :inpatient_care, foreign_key: :ic_id, class_name: 'InpatientCare'
belongs_to :creator, foreign_key: :creator_id, class_name: 'VosUser'
belongs_to :clinical_record, foreign_key: :clinical_record_id, class_name: 'ClinicalRecord'

validates_presence_of :inpatient_care, :creator, :scheduled_time, :actable_id, :actable_type
end

and the following derived class:

class IcReadTemperatureAction < ActiveRecord::Base
acts_as :ic_action
self.table_name = 'powerpet_ic_read_temperature_actions'
end

When i try to 'new' or 'create' the IcReadTemperatureAction class object, it fails with the error in the title. The base class table has the fields actable_id and actable_type as instructed.

Any ideas?

No way to use includes in ActiveRecord to avoid n+1 queries in views?

It doesn't seem there is a way to avoid n+1 queries when using acts_as:

$ store = Store.includes(:products).where(id: 1).first
=>
Store Load SELECT stores SELECT 'stores'.* FROM 'stores' WHERE 'id' = 1
Products Load SELECT products SELECT 'products'.* FROM 'products' WHERE 'products'.'actable_id' = 1
$

Note it's not preloading Book or Pen.

If you're showing an index page that uses data from "specific" (or the actual classes that are acts_as :product) it generates additional queries, and there is no way to seemingly avoid this.

For example you might have workflow states that in the Pen class are defined as "full", "half-full", "empty"; and in Book "on_shelf", "on_loan" ... so you have different workflow_actions specific to their type. So you could imagine an index view where you want to show the status of each product and so having to call product.specific.workflow_state on each one results in a query (which is bad).

Is there something I'm missing? You should be able to preload everything so there are a minimum set of queries (e.g. pull the store, all products, and all related pens and books). But you cannot really say includes(products: [:specific]) or even includes(products: [:book, :pen]) (assuming you knew all the actable classes for product) because Product doesn't have any real association to Book or Pen.

Is there some other strategy around dealing with this, which I'd imagine is a common use case?

Does not work with rails 5

Since the gem is using a pessimistic version constraint for ActiveRecord, this gem doesn't work with Rails 5.

Bundler could not find compatible versions for gem "activerecord":
  In Gemfile:
    active_record-acts_as was resolved to 1.0.0, which depends on
      activerecord (~> 4.1.2)

    rails (< 5.1, >= 5.0.0.rc1) was resolved to 5.0.0.rc1, which depends on
      activerecord (= 5.0.0.rc1)

Other ActiveRecord query methods don't use overridden 'where'

At the moment, due to the overridden where method in ActiveRecord::ActsAs::Querying, you've also had to override find_by and find_by! (which are exact copies of their original methods.

The problem I've faced is now wanting to use something like find_or_initialize_by which when called, throws an exception because it's not using the overriding where method.

Have you got any ideas on how to refactor these query methods, so that only the where method needs to be extended? I'm researching as well, but thought I'd throw it out there.

As an aside, thank you very much for this gem - it's helped us very much. We had used citier before in a rails 3 project, but it hasn't been updated for rails 4+ and seems to be abandoned now.

[Feature Request] Adding accepts_nested_attributes_for actable model

I'm building a testing tool that gets, sets parameters for active_record resources, and it gets tripped up when working with my models that use active_record-acts_as. I was a little surprised to find that the parent object does not accept nested attributes for acts_as attributes. Example below

class NightReport < ActiveRecord::Base
  acts_as :report
  # with attribute :night_supervisor 
end

class Report < ActiveRecord::Base
  actable 
  # with attribute :date 
end

$ NightReport.new( {:night_supervisor => "Nick B", :report_attributes => { :date => Date.today } )
$ ActiveRecord::UnknownAttributeError: unknown attribute: report_attributes

I understand this capability is a little strange ("In which scenario would you want to send attributes with report_attributes => {} ?" ). Tough to explain briefly, but it has to do with the fact that the night_report.attributes list does not include report.attributes.

Are there any adverse effects to adding this capability?

I'd be happy to write up the specs, submit pull request myself.

Thanks for the gem!

-Nick

EDIT: removed section about it appearing to already accept nested attributes

has_one with sub class does not work

Given these models:

class Photo < ActiveRecord::Base
  actable
  belongs_to :user
end

class Avatar < ActiveRecord::Base
  acts_as :photo
end

class User < ActiveRecord::Base
  has_one :avatar
  has_many :photos
end

When I call user.avatar it raises an error like this:

ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:  column avatars.user_id does not exist

It seems that we haven't supported this feature yet. Is there anyway we can work around this?
Thanks.

accessing #acting_as through association returns the wrong actable

There seems to be a problem if you have a circular dependency in your actable base class.

Example:

class Product < ActiveRecord::Base
  actable
  belongs_to :pen_case
end

class Pen < ActiveRecord::Base
  acts_as :product
end

class PenCase < ActiveRecord::Base
  acts_as :product
  has_many :products
end

As you can see Product has a reference pen_case_id to PenCase, which again, is a Product.

Now, this happens:

>> PenCase.first.products
+----+------------+--------------+-------------+--------+-------+
| id | actable_id | actable_type | pen_case_id | name   | price |
+----+------------+--------------+-------------+--------+-------+
| 1  | 1          | Pen          | 1           | Penie! | 0.8   |
+----+------------+--------------+-------------+--------+-------+
1 row in set
>> Pen.first.product.id
=> 1
>> PenCase.first.product.id
=> 2
>> Pen.first.pen_case.product.id
=> 1

As you can see accessing #product (or #acting_as) gives the wrong result if we go through the Product#pen_case association. Weird?

Child class does not inherit parent scopes

If I have

class Product
  actable
  scope :no_users, -> { where(user_id: nil) }
end

and

class Pen
  acts_as :product
end

I can't seem to use Pen.no_users - it throws error: undefined method 'no_users' for Pen

Broken queries when used in conjunction with friendly_id and globalize

When using acts_as in conjunction with friendly_id and globalize, the finders on the model get broken due to an incorrect WHERE condition injected in the query (parent_model.child_model_translations.slug = ? where it should have been child_model_translations.slug = ?).

Models:

class Collection < ActiveRecord::Base
  extend FriendlyId

  translates :name, :slug
  friendly_id :name, use: :globalize
  acts_as :box
end

class Box < ActiveRecord::Base
  default_scope -> { where(in_home: true) }
  acts_as_list scope: [:in_home]
  actable
end

My schema.rb (relevant portions):

  create_table "boxes", force: true do |t|
    t.integer  "actable_id"
    t.string   "actable_type"
    t.integer  "position",     default: 0
    t.boolean  "in_home",      default: false
    t.boolean  "featured",     default: false
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "collection_translations", force: true do |t|
    t.integer  "collection_id", null: false
    t.string   "locale",        null: false
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "name"
    t.string   "slug"
  end

  create_table "collections", force: true do |t|
    t.string   "name"
    t.string   "icon"
    t.string   "image"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "color"
    t.string   "slug"
  end

Gem versions (from bundle show)

 * active_record-acts_as (1.0.2)
 * activerecord (4.1.8)
 * friendly_id (5.0.4)
 * friendly_id-globalize (1.0.0.alpha1 058f863)
 * globalize (4.0.3)

Exception raised when invoking, e.g., Collection.friendly.find('autumn-winter') or Collection.find_by_slug('autumn-winter'):

PG::UndefinedColumn: ERROR:  column boxes.collection_translations.slug does not exist
LINE 1: ... = 'Collection' AND "boxes"."in_home" = 't' WHERE "boxes"."c...
                                                             ^
: SELECT  "collections"."id" AS t0_r0, "collections"."name" AS t0_r1, "collections"."icon" AS t0_r2, "collections"."image" AS t0_r3, "collections"."created_at" AS t0_r4, "collections"."updated_at" AS t0_r5, "collections"."color" AS t0_r6, "collections"."slug" AS t0_r7, "boxes"."id" AS t1_r0, "boxes"."actable_id" AS t1_r1, "boxes"."actable_type" AS t1_r2, "boxes"."position" AS t1_r3, "boxes"."in_home" AS t1_r4, "boxes"."featured" AS t1_r5, "boxes"."created_at" AS t1_r6, "boxes"."updated_at" AS t1_r7 FROM "collections" INNER JOIN "collection_translations" ON "collection_translations"."collection_id" = "collections"."id" LEFT OUTER JOIN "boxes" ON "boxes"."actable_id" = "collections"."id" AND "boxes"."actable_type" = 'Collection' AND "boxes"."in_home" = 't' WHERE "boxes"."collection_translations.slug" = 'autumn-winter' AND "collection_translations"."locale" = 'en' LIMIT 1
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:  column boxes.collection_translations.slug does not exist
LINE 1: ... = 'Collection' AND "boxes"."in_home" = 't' WHERE "boxes"."c...
                                                             ^
: SELECT  "collections"."id" AS t0_r0, "collections"."name" AS t0_r1, "collections"."icon" AS t0_r2, "collections"."image" AS t0_r3, "collections"."created_at" AS t0_r4, "collections"."updated_at" AS t0_r5, "collections"."color" AS t0_r6, "collections"."slug" AS t0_r7, "boxes"."id" AS t1_r0, "boxes"."actable_id" AS t1_r1, "boxes"."actable_type" AS t1_r2, "boxes"."position" AS t1_r3, "boxes"."in_home" AS t1_r4, "boxes"."featured" AS t1_r5, "boxes"."created_at" AS t1_r6, "boxes"."updated_at" AS t1_r7 FROM "collections" INNER JOIN "collection_translations" ON "collection_translations"."collection_id" = "collections"."id" LEFT OUTER JOIN "boxes" ON "boxes"."actable_id" = "collections"."id" AND "boxes"."actable_type" = 'Collection' AND "boxes"."in_home" = 't' WHERE "boxes"."collection_translations.slug" = 'autumn-winter' AND "collection_translations"."locale" = 'en' LIMIT 1
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/postgresql_adapter.rb:822:in `async_exec'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/postgresql_adapter.rb:822:in `block in exec_no_cache'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/abstract_adapter.rb:373:in `block in log'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/abstract_adapter.rb:367:in `log'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/postgresql_adapter.rb:822:in `exec_no_cache'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/postgresql/database_statements.rb:137:in `exec_query'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/postgresql_adapter.rb:954:in `select'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/abstract/database_statements.rb:24:in `select_all'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/connection_adapters/abstract/query_cache.rb:70:in `select_all'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/relation/finder_methods.rb:347:in `find_with_associations'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/relation.rb:611:in `exec_queries'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/relation.rb:493:in `load'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/relation.rb:238:in `to_a'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/relation/finder_methods.rb:460:in `find_take'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/relation/finder_methods.rb:98:in `take'
... 6 levels...
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:247:in `require'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:247:in `block in require'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:232:in `load_dependency'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:247:in `require'
    from /vagrant/bin/rails:8:in `<top (required)>'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:241:in `load'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:241:in `block in load'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:232:in `load_dependency'
    from /opt/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.1.8/lib/active_support/dependencies.rb:241:in `load'
    from /opt/rbenv/versions/2.1.5/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /opt/rbenv/versions/2.1.5/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from -e:1:in `<main>'

Full query that triggered the exception:

SELECT  "collections"."id" AS t0_r0, "collections"."name" AS t0_r1, "collections"."icon" AS t0_r2, "collections"."image" AS t0_r3, "collections"."created_at" AS t0_r4, "collections"."updated_at" AS t0_r5, "collections"."color" AS t0_r6, "collections"."slug" AS t0_r7, "boxes"."id" AS t1_r0, "boxes"."actable_id" AS t1_r1, "boxes"."actable_type" AS t1_r2, "boxes"."position" AS t1_r3, "boxes"."in_home" AS t1_r4, "boxes"."featured" AS t1_r5, "boxes"."created_at" AS t1_r6, "boxes"."updated_at" AS t1_r7 FROM "collections" INNER JOIN "collection_translations" ON "collection_translations"."collection_id" = "collections"."id" LEFT OUTER JOIN "boxes" ON "boxes"."actable_id" = "collections"."id" AND "boxes"."actable_type" = 'Collection' AND "boxes"."in_home" = 't' WHERE "boxes"."collection_translations.slug" = 'autumn-winter' AND "collection_translations"."locale" = 'en' LIMIT 1

What the query looks like without acts_as:

SELECT  "collections".* FROM "collections" INNER JOIN "collection_translations" ON "collection_translations"."collection_id" = "collections"."id" WHERE "collection_translations"."slug" = 'autumn-winter' AND "collection_translations"."locale" = 'en' LIMIT 1

actable class overrides attributes and activerecord hooks of acts_as class even though no instance relationship is specified

Migration :

class SetupTables < ActiveRecord::Migration
  def change
    create_table :wines do |t|
      t.column :name, :string, null: false, limit: 40
    end
    create_table :items do |t|
      t.column :name, :string, null: false, limit: 40
      t.actable
    end
  end
end

Models :

class Item < ActiveRecord::Base
    actable
end
class Wine < ActiveRecord::Base
    acts_as :item, autosave: false
end

Testing :

bundle exec rake db:migrate RAILS_ENV=test
bundle exec rails c test
w = Wine.new(name: 'Merlot')
  • At this point, I see the console output #<Wine id: nil, name: nil> - what gives? All I did was create a basic Wine object, and there are no Item instances stored in the DB or in-memory that point to this object.
w.name = 'Merlot'
w
  • At this point, I see the console output #<Wine id: nil, name: "Merlot"> as it should have in the first place.

Further testing reveals that upon saving the Wine object, the Item activerecord validation method is invoked. This makes no sense to me. I can only surmise that the reason why the Wine object's name was nil at first was because it was being read from Item instead; though I can't see how considering there was no Item object instantiated anywhere. For that matter, nowhere along the line was any association with an instance of Item ever made.

This is a contrived example based off of the problems I've been having running my rspec tests.

Does attributes order matter on creation?

Hi,

I'm a little confused with this bug. First some code:

class Company < ActiveRecord::Base
  acts_as :entity
  has_many :company_markets
  has_many :markets, through: :company_markets

  def market_ids
    # getter for market_ids
  end

  def market_ids=
    # setter for market_ids
  end
end

class Entity < ActiveRecord::Base
  # as a name attribute
  actable
end

I should also add I have a non-null constraint on the entity.name database table row.

Now the confusion:

Company.create(market_ids: [1, 2], name: 'test') will fail throwing PG::NotNullViolation: ERROR: null value in column "name" violates not-null constraint meaning the entity was created without the name I gave it.

But Company.create(name: 'test', market_ids: [1, 2]) will work. Huh?

So I was curious if that a normal behaviour or not. If not I could look at the code and do a PR. Let me know.

model.specific returns nil

I am migrating from act_as_relation and I have the current architecture

merchant_account.rb

class MerchantAccount < ActiveRecord::Base
  actable
end

test_merchant_account.rb

class TestMerchantAccount < ActiveRecord::Base
  acts_as :merchant_account, as: :as_merchant_account
end

Then I can properly create a merchant account object, but can't call specific on the generic object

test = TestMerchantAccount.create(name: "test")
test.merchant_account.specific => nil

As a FYI my merchant account model contains a as_merchant_account_id and as_merchant_account_type

Any idea on why specific is not working?

Creating subclass does not create superclass object until superclass object is needed

the definition of the acts_as association does not implicitly build the superclass object, only accessing it through #actable would.

I propose implementing another method with the same name as the association which calls super or builds the superclass object, then aliasing actable to that method instead.

If this is okay with you, I'd quickly write a PR

NameError: Undefined local variable or method actable

Hello,
I creates a simulate multiple table inheritance, Categories (Clothing, Car, Shoes, ...)

categorie.rb

class Categorie < ActiveRecord::Base
    actable
    validates_presence_of :nom_categorie
    has_many :annonces
end

clothing.rb

class Clothing < ActiveRecord::Base
    acts_as :categorie
end

And after, when I try to getting all the categories in annonce controller,

@categories = Categorie.all

I across this error.

How can I fix it?

Method of parent called on child gives strange results

Following classes:
class Product < ActiveRecord::Base
actable
validates_presence_of :name
def display
puts "I like: #{self.name} as product.."
end
end

class Book < ActiveRecord::Base
actable
acts_as :product
validates_presence_of :title
end

class Dictionary < ActiveRecord::Base
acts_as :book
validates_presence_of :language
end

gives the following result when calling method display on a Book object:

2.1.0 :001 > a=Book.new
=> #<Book id: nil, actable_id: nil, actable_type: nil, title: nil, author: nil>
2.1.0 :002 > a.name='My book'
=> "My book"
2.1.0 :003 > a.display

Book:0x000000059fbdc0 => nil

What is wrong? I expect that the display method prints the line:
'I like: My book as product'.
Versions:
ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
rails -v
Rails 4.1.2

Child Class does not inherit Parent's class methods

The Child class does inherit the instance methods, but not the class methods. Is this expected behavior?

Here's a short code example

class Report < ActiveRecord::Base
  actable

  def self.current(user)
    where(:status => "open").accessible_by(user)
  end
end

class NightSupervisorReport < ActiveRecord::Base
  acts_as :report
end 

In the console

$ Report.current(User.first)
 => #<ActiveRecord::Relation []> 
$ NightSupervisorReport.current(User.first)
NoMethodError: undefined method `current' for #<Class:0x007f8fd4a206c8>

Destroy order

User is plain devise model (email/password)

Customer acts_as User and has_one Company

class User < ActiveRecord:Base
end

class Customer < ActiveRecord::Base
  acts_as :user

  has_one :company
end

If call destroy on customer it will fail because of 'PG::ForeignKeyViolation: ERROR: update or delete on table "customers" violates foreign key constraint "companies_customer_id_fk" on table "companies"'

Customer.first.destroy

But if Customer defined with acts_as as last one (after all relations):

class Customer < ActiveRecord::Base
  has_one :company

  acts_as :user
end

Destroy will succeed.

So, i guess acts_as should be added as last reflection.

Also, delete from companies was called twice: one query as concatenated and other parameterized:

  SQL (0.8ms)  DELETE FROM "customers" WHERE "customers"."id" = 2
  SQL (0.2ms)  DELETE FROM "users" WHERE "users"."id" = $1  [["id", 5]]
  SQL (0.2ms)  DELETE FROM "customers" WHERE "customers"."id" = $1  [["id", 2]]

Maybe this can help.

I would like to fix it, but little advice (and if it is doable at all?) would be good.

Thanks!

Type cast

When I tried Test::Owner.new(super_classes: [Test::SubClassA.new]) I got this error

ActiveRecord::AssociationTypeMismatch: Test::SuperClass(#46400904) expected, got Test::SubClassA(#46395720)

I know that I specified class_name: 'Test::SuperClass', however in your example for store, you could use << to add generic objects

How to use << and add generic type objects?

When given:

# super_class.rb
class Test::SuperClass < ActiveRecord::Base
  actable as: :superclassable
end

# sub_class_a.rb
class Test::SubClassA < ActiveRecord::Base
  acts_as :super_class, as: :superclassable, class_name: 'Test::SuperClass'
end

# sub_class_b.rb
class Test::SubClassB < ActiveRecord::Base
  acts_as :super_class, as: :superclassable, class_name: 'Test::SuperClass'
end

# owner.rb, has_many actables
class Test::Owner < ActiveRecord::
  has_many :super_classes, as: :superclassable, class_name: 'Test::SuperClass'
end

Thanks!

Create actable plus related acts_as product

Not as much an issue as a question i have for my needs.
I get it when I create a Pen, it will automatically also create a Product (examples from the docs).
Which is all fine. But in this case I have to create Pen... which is a bit counter intuitive to me.
In reality i will always create new Product, which happens to be of Pen type.

So what I would basically try to ask is whether it is possible to have something like this in a view:

  • new product
  • select that it is a Pen
  • open additional Pen related attributes
  • create Product with Pen

As far as i am testing it, there is actually no way to create Product and related Pen records.
Only vice-versa.

Wouldn't be easier to have one (although more complex) form, than a separate forms for each of the types? I could be shooting in totally different direction and MTI is not even good solution to do it...in that case I would really appreciate any tips or tricks :)

Object does not keeps the attributes submited

When I submit:

post :create, exam: { name: 'name', description: nil }

And validation fails because description is mandatory:

if @exam.save
else
  render :new
end

The @exam object does not keeps the submited value.

<%= f.text_field :name %> # nil

I need to manually set the acting_as data:

@exam.attributes = create_params

Even the errors:

@exam.acting_as.errors.each do |key, value|
  @exam.errors.add key, value
end

Uses delegate on model does not works for the attributes and I do not found a way to delegate the errors.

I missing something here or it is the normal behavior?

Thanks e congrats for the great gem. (:

Child class without table

Is it posible to extend a base class without creating a new table?

I have a set of child classes with specifc tables. Now i need to create another with the same attributes from base class, but with specific behavior.

It's there any recommended strategy to achieve this?

Thanks in advance!

Parent class does not have child methods.

So I'm trying to convert from acts_as_relation gem to this one.

The issue that I'm having is I'm trying to get all on the superclass and then use the child's methods on the superclass. I know it's something I can do using act_as_relation, but I can't seem to get it to work using this gem. I got it so that all the child classes have the superclass methods, do I have to do something different to get the reverse?

Classes are as follows:

class Clm < ActiveRecord::Base
  actable as: :clmible

  def hachacha
    puts "hachacha"
  end
end
class Hamsclm < ActiveRecord::Base
  acts_as :clm, as: :clmible

  def shabladoo
    puts "shabladoo"
  end
end
class Sfooclm < ActiveRecord::Base
  acts_as :clm, as: :clmible
end

Migrations:

class CreateClms < ActiveRecord::Migration
  def change
    create_table :clms do |t|
      t.actable as: :clmible

      t.timestamps null: false
    end
  end
end
class CreateHamsclms < ActiveRecord::Migration
  def change
    create_table :hamsclms do |t|
      t.string :name

      t.timestamps null: false
    end
  end
end
class CreateSfooclms < ActiveRecord::Migration
  def change
    create_table :sfooclms do |t|
      t.string :name

      t.timestamps null: false
    end
  end
end

What I'm trying to do is

@clms = Clm.all
@clms.each do |clm|
puts clm.name
end

I end up with the following error:

NoMethodError: undefined method `name' for #<Clm:0x007fa5f319dcf0>

Can I even do this with this gem or do I have to go back to the acts_as_relational gem?

"SELECT something AS ..." does not work in the child class

I have the following structure:

class Listing < ActiveRecord::Base
actable
end

class Job < ActiveRecord::Base
acts_as :listing
end

When I run the query like:

Listing.select('listings.*, some_calculations AS distance').first.distance

It returns the correct "distance" value.

BUT when I run the query:

Job.select('jobs.*, some_calculations AS distance').first.distance

the "distance" is undefined. The attributes don't contain "distance" field.

Need help. Thanks.

"undefined local variable or method 'actable'"

Hi there,

I am trying to use the gem for the first time (I also just got started with rails) and I am running into this error message:
"undefined local variable or method 'actable'"

Note that I have installed the gem, added it to my gemfile. I have also added activerecord (https://rubygems.org/gems/activerecord/versions/4.2.4).
I then ran bundle install and all went well.

But now, whenever I am trying to access my "super class" or one of its children, I get the error message. I am sure there is some configuration I am missing but cannot figure out for the life of me what it might be.

Cheers,

Follow rspec convention when including matchers

In master, matchers were merged in #52.

Instructions were to require "rspec/acts_as_matchers". My current rails_helper file looks like:

require 'rspec/rails'
require 'shoulda/matchers'
require 'cancan/matchers'

Maybe we should call it 'active_record/acts_as/matchers' instead

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.