3

나는 has_many roles= 속성이 항상 영속적 인 방식으로 작동한다는 것을 보여주는 다음 스크립트를 가지고있다.has_many 연관 속성 setter는 항상 해당 값을 데이터베이스에 유지하며 그렇게하지 않을 수 있습니까?

내 질문은 :

1)이 동작 뒤에 이유 무엇입니까 : 왜 has_many 속성 바로 그들이 설정 한 순간에 지속되는가? 왜 이런 일반적인 속성 동작 (다음 스크립트의 name)과 다른 점이 있습니까?

2) 사용자 정의 roles= 설정기를 작성할 수 있으므로 롤 없이도 모델 속성 (롤 = 포함)을 유지하려면 fx assign_attributes을 사용할 수 있습니까? Rails> 3.2에서 가능하다면 예제가 좋을까요?

gem 'rails', '>=3.2.0' # change as required 
gem 'sqlite3' 

require 'active_record' 
require 'logger' 

puts "Active Record #{ActiveRecord::VERSION::STRING}" 
ActiveRecord::Base.logger = Logger.new(STDERR) 

ActiveRecord::Base.establish_connection(
    :adapter => 'sqlite3', 
    :database => ':memory:' 
) 

ActiveRecord::Schema.define do 
    create_table :users, :force => true do |t| 
    t.string :name 
    end 

    create_table :user_roles, :force => true do |t| 
    t.integer :user_id 
    t.integer :role_id 
    end 

    create_table :roles, :force => true do |t| 
    t.string :name 
    end 
end 

# Create the minimal set of models to reproduce the bug 
class User < ActiveRecord::Base 
    has_many :user_roles 
    has_many :roles, :through => :user_roles 
end 

class UserRole < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :role 
end 

class Role < ActiveRecord::Base 
end 

r = Role.create(:name => 'admin') 
u = User.create 

# roles= persists its value, name= does not 
u.assign_attributes({ :roles => [r], :name => 'Stanislaw' }) 

# The same behavior is produced by: 
# u.attributes= 
# u.roles= 

puts "name attribute: #{u.name}" 
puts "many roles #{u.roles}" 

u.reload 

puts "name attribute: #{u.name}" 
puts "many roles #{u.roles}" # I see admin role and I want to achieve behavior that I would not see it 

답변

3

협회는 속성과 동일하지 않습니다 : 여기에

는 스크립트입니다. 예를 들어, has_many 연관을 사용하면 할당 할 때 할 일은 belongs_to 측에서 외래 키를 설정하는 것입니다. UserRole 레코드를 생성하는 사용자에게 역할을 할당 조인 테이블과 설정 USER_ID/ROLE_ID 기록하여 예에서

class User < ActiveRecord::Base 
    has_many :posts 
end 

class Post < ActiveRecord::Base 
    belongs_to :user 
end 

p = Post.create 
u = User.create 
u.posts << p # this line will simply update p.user_id with u.id 

. has_many :through

이 동작을 방지하는 방법으로 레코드를 저장 한 다음 연결을 만들 때까지 고정 된 역할을 저장하는 가상 특성을 사용할 수 있습니다.

class User < ActiveRecord::Base 
    attr_accessor :unpersisted_roles 
    attr_accessible :unpersisted_roles 

    after_save :assign_roles 

    def assign_roles 
    self.roles << @unpersisted_roles if defined(@unpersisted_roles) 
    end 
end 

r = Role.create 
u = User.create 
u.attributes = {:unpersisted_roles => [r]} 
u.save # roles get persisted here 

이는 간단한 예입니다, 실제 코드는 더 복잡하거나 너무 많은 부작용없이 작업을 진행하게 깊은 AR의 인터페이스로 다이빙을 필요로 할 수도 있습니다.

당신이 협회를 계속 유지하고 싶지 않은 이유에 대해 약간의 통찰력을 줄 수 있다면 좀 더 구체적인 행동 방침을 제안 할 수있을 것입니다. 변경 사항이 몇 가지 의견 Issue #3을 참조에서



업데이트

.

module SimpleRoles 
    module Many 
    module Persistence 
     class << self 
     def included base 
      base.class_eval %{ 
      has_many :user_roles 
      has_many :roles, :through => :user_roles 
      # Add a callback to persist the roles 
      after_create :persist_roles 
      } 
     end 
     end 

     def roles 
     # Apply unpersisted roles in case we want to access them before saving 
     super.map(&:name).map(&:to_sym) + (@unpersisted_roles || []) 
     end 

     def roles= *rolez 
     rolez.to_symbols!.flatten! 

     # if we're already persisted then go ahead and save 
     # otherwise stash them in an ivar array 
     if persisted? 
      super retrieve_roles(rolez) 
     else 
      @unpersisted_roles = rolez 
     end 
     end 

     private 

     # Our callback method that sets the roles, this will 
     # work since persisted? is true when this runs. 
     def persist_roles 
     self.roles = @unpersisted_roles 
     end 

     def retrieve_roles rolez 
     raise "Not a valid role!" if (rolez - config.valid_roles).size > 0 

     rolez.map do |rolle| 
      begin 
      Role.find_by_name! rolle.to_s 
      rescue 
      raise "Couldn't find Role for #{rolle}. Maybe you need to re-run migrations?" 
      end 
     end 
     end 

     def config 
     SimpleRoles::Configuration 
     end 
    end 
    end 
end 
+0

답해 주셔서 감사합니다. 나는 확실하지 않다, 나는 정말로 "지속하지 않는다"싶다. 원래 문제는 https://github.com/stanislaw/simple_roles/issues/3입니다. 이것은 오히려 오래된 프로젝트이며, 아마도 내가 거기에 역할 인터페이스를 완전히 재고 할 필요가있을 것입니다. 기억하십시오 : 나는이 링크를 게시하여 두뇌를 과도하게 사용하지는 않겠지 만, 좋은 조언에 대해 정말 감사 할 것입니다. –

+0

아아, 나는 그 문제에서 사용자를 지속시키고 있습니다. 연결을 구축하기 위해서는 사용자를 유지해야하는 사용자 ID가 필요합니다. 따라서 레일스는 정보를 잃어버린 것처럼 계속 유지합니다. 가능한 해결책으로 업데이트하겠습니다. – Cluster

+0

아주 그렇습니다! 당신의 노력에 감사드립니다! –