What is causing this ActiveRecord::ReadOnlyRecord error?

后端 未结 6 673
我寻月下人不归
我寻月下人不归 2020-12-07 08:18

This follows this prior question, which was answered. I actually discovered I could remove a join from that query, so now the working query is

start_cards =          


        
相关标签:
6条回答
  • 2020-12-07 08:40

    Instead of find_by_sql, you can specify a :select on the finder and everything's happy again...

    start_cards = DeckCard.find :all, :select => 'deck_cards.*', :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]

    0 讨论(0)
  • 2020-12-07 08:41

    This might have changed in recent release of Rails, but the appropriate way to solve this problem is to add :readonly => false to the find options.

    0 讨论(0)
  • 2020-12-07 08:45

    select('*') seems to fix this in Rails 3.2:

    > Contact.select('*').joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly?
    => false
    

    Just to verify, omitting select('*') does produce a readonly record:

    > Contact.joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly?
    => true
    

    Can't say I understand the rationale but at least it's a quick and clean workaround.

    0 讨论(0)
  • 2020-12-07 08:47

    To deactivate it...

    module DeactivateImplicitReadonly
      def custom_join_sql(*args)
        result = super
        @implicit_readonly = false
        result
      end
    end
    ActiveRecord::Relation.send :include, DeactivateImplicitReadonly
    
    0 讨论(0)
  • 2020-12-07 08:56

    Or in Rails 3 you can use the readonly method (replace "..." with your conditions):

    ( Deck.joins(:card) & Card.where('...') ).readonly(false)
    
    0 讨论(0)
  • 2020-12-07 08:57

    Rails 2.3.3 and lower

    From the ActiveRecord CHANGELOG(v1.12.0, October 16th, 2005):

    Introduce read-only records. If you call object.readonly! then it will mark the object as read-only and raise ReadOnlyRecord if you call object.save. object.readonly? reports whether the object is read-only. Passing :readonly => true to any finder method will mark returned records as read-only. The :joins option now implies :readonly, so if you use this option, saving the same record will now fail. Use find_by_sql to work around.

    Using find_by_sql is not really an alternative as it returns raw row/column data, not ActiveRecords. You have two options:

    1. Force the instance variable @readonly to false in the record (hack)
    2. Use :include => :card instead of :join => :card

    Rails 2.3.4 and above

    Most of the above no longer holds true, after September 10 2012:

    • using Record.find_by_sql is a viable option
    • :readonly => true is automatically inferred only if :joins was specified without an explicit :select nor an explicit (or finder-scope-inherited) :readonly option (see the implementation of set_readonly_option! in active_record/base.rb for Rails 2.3.4, or the implementation of to_a in active_record/relation.rb and of custom_join_sql in active_record/relation/query_methods.rb for Rails 3.0.0)
    • however, :readonly => true is always automatically inferred in has_and_belongs_to_many if the join table has more than the two foreign keys columns and :joins was specified without an explicit :select (i.e. user-supplied :readonly values are ignored -- see finding_with_ambiguous_select? in active_record/associations/has_and_belongs_to_many_association.rb.)
    • in conclusion, unless dealing with a special join table and has_and_belongs_to_many, then @aaronrustad's answer applies just fine in Rails 2.3.4 and 3.0.0.
    • do not use :includes if you want to achieve an INNER JOIN (:includes implies a LEFT OUTER JOIN, which is less selective and less efficient than INNER JOIN.)
    0 讨论(0)
提交回复
热议问题