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 = DeckCard.find :all, :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]
This appears to work. However, when I try to move these DeckCards into another association, I get the ActiveRecord::ReadOnlyRecord error.
Here's the code
for player in @game.players
player.tableau = Tableau.new
start_card = start_cards.pop
start_card.draw_pile = false
player.tableau.deck_cards << start_card # the error occurs on this line
end
and the relevant Models (tableau are the players cards on the table)
class Player < ActiveRecord::Base
belongs_to :game
belongs_to :user
has_one :hand
has_one :tableau
end
class Tableau < ActiveRecord::Base
belongs_to :player
has_many :deck_cards
end
class DeckCard < ActiveRecord::Base
belongs_to :card
belongs_to :deck
end
I am doing a similar action just after this code, adding DeckCards
to the players hand, and that code is working fine. I wondered if I needed belongs_to :tableau
in the DeckCard Model, but it works fine for the adding to player's hand. I do have a tableau_id
and hand_id
columns in the DeckCard table.
I looked up ReadOnlyRecord in the rails api, and it doesn't say much beyond the description.
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:
@readonly
to false in the record (hack) :include => :card
instead of :join => :card
Rails 2.3.4 and above
Most of the above no longer holds true, after September 10 2012:
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) :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
(ie user-supplied :readonly
values are ignored -- see finding_with_ambiguous_select?
in active_record/associations/has_and_belongs_to_many_association.rb
.) has_and_belongs_to_many
, then @aaronrustad
's answer applies just fine in Rails 2.3.4 and 3.0.0. :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
.) 或者在Rails 3中,您可以使用readonly方法(将“...”替换为您的条件):
( Deck.joins(:card) & Card.where('...') ).readonly(false)
这可能在最近发布的Rails中已经改变,但解决此问题的适当方法是在find选项中添加:readonly => false 。
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.
而不是find_by_sql,你可以在finder上指定一个:select,一切都很开心......
start_cards = DeckCard.find :all, :select => 'deck_cards.*', :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]
To deactivate it...
module DeactivateImplicitReadonly
def custom_join_sql(*args)
result = super
@implicit_readonly = false
result
end
end
ActiveRecord::Relation.send :include, DeactivateImplicitReadonly
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.