Association with scope in Ruby on Rails

9

I have a Ruby on Rails application in which I have licenses, items that can be licensed, and a table that lists the two (What items in what quantity are present in the license?). Analogously to the items in a shopping cart.

Some of the items will no longer be marketed, but I want to keep them in the database. I then created a soft-delete and used a default scope for the template and for the relationships. But when I try to change existing records using the related model, I get an exception: ActiveRecord::ReadOnlyRecord

My templates look like this:

class Item < ActiveRecord::Base
  default_scope { where(deleted:false) }
end

class LicenseItem < ActiveRecord::Base
  belongs_to :license, touch: true
  belongs_to :item
end

class License < ActiveRecord::Base
  has_many :license_items,  
          -> { joins(:item).where(items: {deleted: false} ) }, 
          dependent: :destroy
end

This way:

pry(main)> License.find(0).license_items[0].readonly?
=> true

Is there any way to make this relationship not just read?

I have tried to add readonly(false) at the end of the scope of has_many to License to no avail.

    
asked by anonymous 13.12.2013 / 19:46

2 answers

6

According to this thread in GitHub , this is a Rails 4.0 bug that has been fixed in the release 4.0.1. Updating your Rails, you can include readonly(false) in your scope and it will work:

class License < ActiveRecord::Base
    has_many :license_items,  
          -> { joins(:item).where(items: {deleted: false}).readonly(false) }, 
          dependent: :destroy
end

To update the Rails version, edit your Gemfile and then run bundle update .

In the latter case, if you can not update the Rails version, you can pass the readonly: false option to the find (not recommended) method:

License.find(1).license_items.find(1, readonly: false).update_attributes(amount: 5)
    
14.12.2013 / 14:36
1

What version of RoR are you using? According to this answer in the English OS, when the "read-only" feature was introduced (in version 1.12.10 ) the default behavior was to infer :readonly => true whenever :joins was used (which I see to be the case with its license_items ). Translating freely from the CHANGELOG (emphasis mine):

  

1.12.0 (October 16th, 2005)

     
  • Introduced read-only records. If you call object.readonly! it will mark the object as read-only and cast ReadOnlyRecord if you call object.save . object.readonly? indicates whether or not the object is read-only. Passing :readonly => true to any finder method will mark the returned records as read-only. The :joins option now means :readonly , so if you use this option, saving the same record will fail . Use find_by_sql as an alternate path.
  •   

However, as of versions 2.3.4 and 3.0.0, the behavior has changed: readonly is only inferred if the :joins option is used without an explicit explicit % or the :select [set to false] option is also explicit (which, if I understand correctly, you've already tried). In some cases ( :readonly ), has_and_belong_to_many is ignored - explicit or not - so the only output is to use :readonly .

The response referenced above contains more details, but unfortunately I do not have enough experience with :select to comment. I suggest using it as a starting point if the above steps do not resolve.

    
14.12.2013 / 11:55