[ruby-on-rails] 이 ActiveRecord :: ReadOnlyRecord 오류의 원인은 무엇입니까?
다음은 이 이전 질문에 대한 답변입니다. 실제로 해당 쿼리에서 조인을 제거 할 수 있음을 발견 했으므로 이제 작동중인 쿼리는
start_cards = DeckCard.find :all, :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]
이것은 작동하는 것 같습니다. 그러나 이러한 DeckCard를 다른 연결로 이동하려고하면 ActiveRecord :: ReadOnlyRecord 오류가 발생합니다.
코드는 다음과 같습니다
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
관련 모델 (테이블은 테이블의 플레이어 카드입니다)
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
이 코드 직후에 비슷한 작업을 수행 DeckCards
하여 플레이어 손에 추가 하면 해당 코드가 제대로 작동합니다. belongs_to :tableau
DeckCard 모델에 필요한지 궁금 했지만 플레이어의 손에 추가하는 것이 좋습니다. DeckCard 테이블에 tableau_id
및 hand_id
열 이 있습니다 .
Rails API에서 ReadOnlyRecord를 찾았으며 설명을 넘어서는 말은 많지 않습니다.
답변
레일 2.3.3 이하
로부터 액티브 CHANGELOG
(v1.12.0 년 10 월 16 일, 2005) :
읽기 전용 레코드를 소개하십시오. object.readonly를 호출하면! 그런 다음 객체를 읽기 전용으로 표시하고 object.save를 호출하면 ReadOnlyRecord를 발생시킵니다. object.readonly? 객체가 읽기 전용인지 여부를보고합니다. 파인더 메소드에 : readonly => true를 전달하면 리턴 된 레코드가 읽기 전용으로 표시됩니다. : joins 옵션은 이제 : readonly를 의미하므로이 옵션을 사용하면 동일한 레코드를 저장할 수 없습니다. find_by_sql을 사용하여 해결하십시오.
를 사용 find_by_sql
하는 것은 실제로 원시 행 / 열 데이터를 반환하므로 대안이 아닙니다 ActiveRecords
. 두 가지 옵션이 있습니다.
@readonly
레코드에서 인스턴스 변수 를 false로 설정 (해킹):include => :card
대신에 사용:join => :card
레일 2.3.4 이상
위의 대부분은 2012 년 9 월 10 일 이후 더 이상 적용되지 않습니다.
- 사용하는
Record.find_by_sql
것입니다 가능한 옵션 :readonly => true
자동으로 유추되는 경우에만 경우:joins
지정 하지 않고 명시 적으로:select
도 (상속 범위 파인더 나) 명시 적:readonly
옵션은 (의 구현 볼 수set_readonly_option!
있는active_record/base.rb
레일 2.3.4에 대한, 또는의 구현to_a
에서active_record/relation.rb
와의custom_join_sql
에서active_record/relation/query_methods.rb
레일 3.0.0를 들어)- 그러나 조인 테이블에 두 개 이상의 외래 키 열이 있고 명시 적으로 지정되지 않은 경우 (예 : 사용자 제공 값은 무시 됩니다 . 참조
:readonly => true
) 항상 자동으로 추론됩니다 .has_and_belongs_to_many
:joins
:select
:readonly
finding_with_ambiguous_select?
active_record/associations/has_and_belongs_to_many_association.rb
- 결론적으로, 특별한 취급하지 않는 테이블에 가입하고
has_and_belongs_to_many
다음@aaronrustad
의 대답은 레일 2.3.4과 3.0.0에서 잘 적용됩니다. - 를 달성하려는 경우 사용 하지 마십시오 (을 의미하며 이는 선택보다 덜 효율적 입니다.)
:includes
INNER JOIN
:includes
LEFT OUTER JOIN
INNER JOIN
답변
또는 Rails 3에서는 읽기 전용 방법을 사용할 수 있습니다 ( “…”을 조건으로 대체).
( Deck.joins(:card) & Card.where('...') ).readonly(false)
답변
최근 Rails 릴리스에서 변경되었을 수 있지만이 문제를 해결하는 적절한 방법은 : readonly => false 를 찾기 옵션 에 추가 하는 것입니다.
답변
select ( ‘*’)는 Rails 3.2에서 이것을 고치는 것 같습니다 :
> Contact.select('*').joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly?
=> false
select ( ‘*’)를 생략하면 읽기 전용 레코드가 생성됩니다.
> Contact.joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly?
=> true
이론적 근거를 이해한다고 말할 수는 없지만 적어도 빠르고 깨끗한 해결 방법입니다.
답변
find_by_sql 대신 파인더에서 : select를 지정하면 모든 것이 행복합니다 …
start_cards = DeckCard.find :all,
:select => 'deck_cards.*',
:joins => [:card],
:conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]
답변
비활성화하려면 …
module DeactivateImplicitReadonly
def custom_join_sql(*args)
result = super
@implicit_readonly = false
result
end
end
ActiveRecord::Relation.send :include, DeactivateImplicitReadonly