2013-06-03 3 views
0

레일 (및 개발)을 처음 사용하고 변경 로그를 만들 필요가 있습니다. 직원 테이블이 있다고 가정 해 봅시다. 이 테이블에는 직원 참조 번호, 이름 및 성이 있습니다. 이름이나 성이 바뀌면 나중에보고 할 수 있도록 테이블에 로그인해야합니다. 나는 단지 변경 사항을 기록하기 만하면됩니다. 그래서 직원 ref 1이 Bill에서 Bob으로 바뀌면 참조 번호와 이름을 테이블에 넣어야합니다. 변경 표에는 한밤에 변경되는 모든 열이있을 수 있지만 대부분이 참조 번호와 변경된 필드로 채워집니다. 이전 값도 필요하지 않습니다. 단지 새로운 값입니다. 의미가있는 희망.레일 변경 로그 만들기

종이 트레일과 같은 보석으로 보였지만, 내가 필요로하는 것은 매우 복잡해 보입니다. 나는 모델을 조작하거나 버전을 옮길 필요가 없다. 나는 언제, 누구에 의해, 어떤 필드가 변경되었는지를 추적 할 필요가있다.

귀하의 권장 사항에 감사드립니다.

+0

나는 paper_trail 또는 vestal_versions을 고집한다고 말하고 싶습니다. 모든 기능이 필요하지는 않지만 작업을 수행하고 많은 오버 헤드가 없습니다. 2 중 paper_trail이 더 활발한 것으로 보입니다. – PinnyM

답변

1

요구 사항을 기반으로 자신 만의 변경 로그를 작성해야한다고 주장하는 경우 몇 가지 콜백을 사용하면됩니다. 당신의 Employee 모델에서

def up 
    create_table :employee_change_logs do |t| 
    t.references :employee 
    # as per your spec - copy all column definitions from your employees table 
    end 
end 

: 먼저 로그 테이블을 만들

class Employee < ActiveRecord::Base 
    has_many :employee_change_logs 

    before_update :capture_changed_columns 
    after_update :log_changed_columns 

    # capture the changes before the update occurs 
    def capture_changed_columns 
    @changed_columns = changed 
    end 

    def log_changed_columns 
    return if @changed_columns.empty? 
    log_entry = employee_change_logs.build 
    @changed_columns.each{|c| log_entry.send(:"#{c}=", self.send(c))} 
    log_entry.save! 
    end 
end 
+0

고마워,이 옳은 길에 나를 넣어! –

+0

한 가지 문제가 있습니다. 로그 테이블에는 변경을 수행 한 current_user에 대한 필드가 있습니다. 그러나 이것을 모델에 전달할 수 없으며 이것이 어쨌든 잘못 될 수 있음을 이해해야합니다. 컨트롤러로 모든 것을 옮겨야합니까? 그렇지 않으면 업데이트 전에 변경 사항을 캡처 할 수있는 기능이 없어지십니까? –

+0

@GarethBurrows : 가장 간단한 해결책은 current_user가 모델 수준에서 액세스 할 수 있는지 확인하는 것입니다.이것은 우려의 분리를 다소 해치지 만 보통은 눈살을 찌푸리게됩니다. 그러나 절대적으로 필요하다면 효과가 있습니다. 또는 컨트롤러의 수정 사용자를 Employee 인스턴스의 가상 속성 (데이터베이스 지원이 아닌)으로 설정할 수 있습니다. 그런 다음이 유효성을 확인하기 위해 before_update 유효성 검증을 추가하고 log_entry를 작성할 때이를 전달하십시오. – PinnyM

1

나는 보석 vestal_versions을 추천합니다.

class User < ActiveRecord::Base 
    versioned 

    validates_presence_of :first_name, :last_name 

    def name 
    "#{first_name} #{last_name}" 
    end 
end 

을 그리고 다음과 같이 사용합니다 : 버전 ActiveRecord 모델에

, 단순히 다음처럼 클래스에 버전 추가 할

우리가 한 첫번째 일은에서 주위 필터를 넣어
@user.update_attributes(:last_name => "Jobs", :updated_by => "Tyler") 
@user.version # => 2 
@user.versions.last.user # => "Tyler" 
0

응용 프로그램 컨트롤러. 이것은 current_employee를 직원 모델로 가져 오는 방법이었습니다. 특히 나 같은 초보자에게는 어려웠습니다.

around_filter :set_employee_for_log, :if => Proc.new { @current_account && 
@current_account.log_employee_changes? && @current_employee } 

def set_employee_for_log 
    Thread.current[:current_employee] = @current_employee.id 
    begin 
     yield 
    ensure 
     Thread.current[:current_employee ] = nil 
    end 
    end 
end 

다음, 로깅이 계정 수준에서 활성화 된 경우 실제로 변경 사항을 캡처하기 위해 약간의 후크를 추가

다음
CHECK_FIELDS = ['first_name', 'last_name', 'middle_name'] 

내가 모니터링에 관심이 필드 내가 정의 된 직원 모델

before_update :capture_changed_columns 
after_update :log_changed_columns, :if => Proc.new { self.account.log_employee_changes? } 

def capture_changed_columns 
    @changed_columns = changed 
    @changes = changes 
end 

def log_changed_columns 
    e = EmployeeChangeLog.new 
    Employee::CHECK_FIELDS.each do |field| 
    if self.send("#{field}_changed?") 
    e.send("#{field}=", self.send(field)) 
    end 
end 

if e.changed? 
    e.update_attribute(:account_id, self.account.id) 
    e.update_attribute(:employee_id, self.id) 
    e.update_attribute(:employee_ref, self.employee_ref) 
    e.update_attribute(:user_id, Thread.current[:current_employee]) 
    e.save 
else return 
end 

그리고 그 것이다. 계정에서 사용 가능하게하면 앱은 특정 필드를 감시하고 해당 필드의 모든 변경 사항을 테이블에 기록하여 간단한 감사 추적을 작성합니다.