2010-08-19 28 views
16

Có thể gửi các biến trong quá trình chuyển đổi không? tức làChuyển biến cho Rails StateMachine chuyển đổi đá quý

@car.crash!(:crashed_by => current_user) 

Tôi có callbacks trong mô hình của tôi, nhưng tôi cần phải gửi cho họ sử dụng người xúi giục quá trình chuyển đổi

after_crash do |car, transition| 
    # Log the car crashers name 
end 

tôi không thể truy cập CURRENT_USER bởi vì tôi là trong mô hình và không điều khiển /Lượt xem.

Và trước khi bạn nói điều đó ... Tôi biết tôi biết.

Đừng cố gắng để truy cập các biến session trong mô hình

tôi nhận được nó.

Tuy nhiên, bất cứ khi nào bạn muốn tạo một cuộc gọi lại để ghi lại hoặc kiểm tra nội dung nào đó thì có khả năng bạn sẽ muốn biết ai đã gây ra nó? Thông thường tôi muốn có một cái gì đó trong bộ điều khiển của tôi rằng đã làm một cái gì đó giống như ...

@foo.some_method(current_user) 

và mô hình Foo của tôi sẽ được mong đợi một số người sử dụng để kích động some_method nhưng làm thế nào để tôi làm điều này với một sự chuyển tiếp với đá quý statemachine?

Trả lời

32

Nếu bạn đang đề cập đến đá quý state_machine - https://github.com/pluginaweek/state_machine - sau đó nó hỗ trợ lập luận sự kiện

after_crash do |car, transition| 
    Log.crash(:car => car, :driver => transition.args.first) 
end 
+2

Bởi trùng hợp ngẫu nhiên, tôi lại gặp trở ngại trong câu hỏi của riêng mình trong tìm kiếm của Google và câu trả lời này rất hữu ích. Cảm ơn. –

+0

Tôi nghĩ rằng điều này chắc chắn là tốt hơn so với User.current mà tôi thấy những người khác thực hiện khi họ chạy vào loại vấn đề này. Tương tác người dùng thuộc lớp điều khiển. –

+2

Điều này hoạt động tốt, nhưng bạn * làm * phải đánh vần chính xác quá trình chuyển đổi. Giải pháp ở trên có thêm 's'. – Brenda

2

Tôi không nghĩ bạn có thể chuyển thông số cho các sự kiện bằng đá quý đó, vì vậy có thể bạn sẽ lưu trữ current_user trên @car (tạm thời) để cuộc gọi kiểm tra của bạn có thể truy cập nó.

Trong điều khiển

@car.driver = current_user 

Trong callback

after_crash do |car, transition| 
    create_audit_log car.driver, transition 
end 

Hoặc một cái gì đó dọc theo những đường .. :)

+0

Cảm ơn Keeran. Đây là cơ bản những gì tôi đã kết thúc làm cuối cùng. Vì thuộc tính không có tính vĩnh cửu - bất kỳ suy nghĩ nào về cách bạn có thể làm điều này mà không tạo ra một trường mới trong DB? –

+0

Bạn có thể thử thêm attr_accessor cho: trình điều khiển, nhưng tôi không chắc chắn nếu cuộc gọi lại sẽ tải lại/sử dụng một trường hợp 'tươi' của mô hình (và do đó lau temp tạm thời). – keeran

7

Tôi đã gặp rắc rối với tất cả các câu trả lời khác, và sau đó tôi thấy rằng bạn chỉ có thể ghi đè lên sự kiện trong lớp học.

class Car 
    state_machine do 
    ... 
    event :crash do 
     transition any => :crashed 
    end 
    end 
    def crash(current_driver) 
    logger.debug(current_driver) 
    super 
    end 
end 

Chỉ cần chắc chắn để gọi là "siêu" trong phương pháp tùy chỉnh của bạn

+0

Đây là câu trả lời dễ nhất, đơn giản nhất, dễ hiểu nhất. –

0

Một mô hình phổ biến (xem state_machine docs) giúp bạn tiết kiệm từ việc phải vượt qua các biến giữa bộ điều khiển và mô hình là để tự động xác định trạng thái phương pháp kiểm tra trong phương thức gọi lại. Điều này sẽ không được rất thanh lịch trong ví dụ ở trên, nhưng có thể là thích hợp hơn trong trường hợp mô hình cần xử lý cùng một biến (s) ở các trạng thái khác nhau.Ví dụ, nếu bạn có 'rơi', 'đánh cắp', và các quốc gia 'mượn' trong mô hình xe của bạn, tất cả đều có thể được kết hợp với một người có trách nhiệm, bạn có thể có:

state :crashed, :stolen, :borrowed do 
    def blameable? 
    true 
    end 

state all - [:crashed, :stolen, :borrowed] do 
    def blameable? 
    false 
    end 

Sau đó, trong bộ điều khiển , bạn có thể làm điều gì đó như:

car.blame_person(person) if car.blameable? 
1

Tôi đã sử dụng giao dịch, thay vì cập nhật đối tượng và thay đổi trạng thái trong một cuộc gọi. Ví dụ: trong hành động cập nhật,

ActiveRecord::Base.transaction do 
    if @car.update_attribute!(:crashed_by => current_user) 
    if @car.crash!() 
     format.html { redirect_to @car } 
    else 
     raise ActiveRecord::Rollback 
    else 
    raise ActiveRecord::Rollback 
    end 
end 
Các vấn đề liên quan