it-source

이 활성 레코드의 원인:ReadOnlyRecord 오류?

criticalcode 2023. 6. 6. 00:02
반응형

이 활성 레코드의 원인: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 :tableauDeckCard 모델에서는 사용할 수 있지만 플레이어의 손에 추가하는 데는 문제가 없습니다.나는 있습니다.tableau_id그리고.hand_id열을 표시할 수 있습니다.

레일즈 API에서 ReadOnly Record를 찾아봤는데 설명 이상의 내용은 없습니다.

레일 2.3.3 이하

활성 레코드에서:

읽기 전용 레코드를 소개합니다.object.readonly!를 호출하면 개체가 읽기 전용으로 표시되고 object.save.object.readonly?를 호출하면 ReadOnlyRecord가 표시됩니다.개체가 읽기 전용인지 여부를 보고합니다.finder 메서드에 :read only => true를 전달하면 반환된 레코드가 읽기 전용으로 표시됩니다.:joins 옵션은 이제 :readonly를 의미하므로 이 옵션을 사용하면 동일한 레코드 저장이 실패합니다.find_by_sql을 사용하여 해결합니다.

사용.find_by_sqlRaw 행/컬럼 데이터를 반환하기 때문에 실제 대안은 아닙니다.ActiveRecords두 가지 옵션이 있습니다.

  1. 인스턴스 변수 강제 적용@readonly기록에 거짓이 있음 (계속)
  2. 사용하다: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_aactive_record/relation.rb그리고 의custom_join_sqlactive_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은 Rails .4.0에 Rails 2.3.4 및 3.0.0 잘 적 용 됩 니 다
  • 사용하지 않음:includes만약 당신이 성취하기를 원한다면.INNER JOIN(:includes을 의미합니다.LEFT OUTER JOIN보다 덜 선택적이고 덜 효율적인.INNER JOIN.)

또는 레일 3에서 읽기 전용 방법을 사용할 수 있습니다("..."을 조건으로 대체).

( Deck.joins(:card) & Card.where('...') ).readonly(false)

이것은 최근 Rails 릴리스에서 변경되었을 수 있지만 이 문제를 해결하는 적절한 방법은 찾기 옵션에 :readonly => false를 추가하는 것입니다.

select('*')는 레일 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

언급URL : https://stackoverflow.com/questions/639171/what-is-causing-this-activerecordreadonlyrecord-error

반응형