15

Tôi muốn đặt thuộc tính lớp khi ứng dụng Rails của tôi khởi động. Nó yêu cầu kiểm tra một số tuyến đường, vì vậy các tuyến cần phải được tải trước khi mã tùy chỉnh của tôi chạy. Tôi gặp khó khăn khi tìm một nơi đáng tin cậy để treo trongTrình khởi tạo đường ray chạy * sau * tuyến được tải?

này hoạt động hoàn hảo trong "test" môi trường:.

config.after_initialize do 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

Nhưng nó không làm việc trong môi trường "phát triển" (các tuyến đường trống)

Hiện tại tôi dường như có những thứ hoạt động trong chế độ phát triển bằng cách chạy cùng mã trong config.to_prepare mà tôi hiểu sẽ xảy ra trước mọi yêu cầu. Thật không may sử dụng to_prepare một mình dường như không hoạt động trong chế độ thử nghiệm, do đó trùng lặp.

Tôi tò mò tại sao các tuyến đường được tải trước khi after_initialize ở chế độ thử nghiệm, nhưng không ở chế độ phát triển. Và thực sự, móc tốt nhất cho điều này là gì? Có một cái móc nào sẽ hoạt động cho mọi môi trường không?

* gợi ý EDIT *

mu của tải lại các tuyến đường là tuyệt vời. Nó cho phép tôi truy cập nhất quán vào các tuyến trong vòng after_initialize trong mọi môi trường. Đối với trường hợp sử dụng của tôi mặc dù, tôi nghĩ rằng tôi vẫn cần phải chạy mã từ to_prepare là tốt, kể từ khi tôi đang thiết lập một thuộc tính lớp trên một mô hình và các mô hình được nạp lại trước mỗi yêu cầu.

Vì vậy, đây là những gì tôi đã kết thúc.

[:after_initialize, :to_prepare].each do |hook| 
    config.send(hook) do 
    User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq 
    end 
end 

Có vẻ như hơi lộn xộn đối với tôi. Tôi nghĩ rằng tôi muốn làm điều gì đó như:

config.after_initialize do 
    User.exclude_routes_from_usernames! 
end 

config.to_prepare do 
    User.exclude_routes_from_usernames! 
end 

Nhưng tôi không chắc chắn nếu User là đúng nơi để được kiểm tra Rails.application.routes. Tôi đoán tôi có thể làm điều tương tự với mã trong lib/nhưng tôi không chắc chắn nếu đó là một trong hai.

Một tùy chọn khác là chỉ áp dụng đề xuất của mu cho to_prepare. Điều đó có tác dụng nhưng có vẻ như có một sự chậm trễ đáng chú ý tải lại các tuyến đường trên mọi yêu cầu trong môi trường dev của tôi, vì vậy tôi không chắc liệu đây có phải là một cuộc gọi tốt hay không, dù ít nhất là DRY.

config.to_prepare do 
    Rails.application.reload_routes! 
    User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq 
end 

Trả lời

22

Bạn có thể buộc các tuyến đường phải được nạp trước khi nhìn vào Rails.application.routes với điều này:

Rails.application.reload_routes! 

Vì vậy, cố gắng này trong config/application.rb của bạn:

config.after_initialize do 
    Rails.application.reload_routes! 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

tôi đã thực hiện điều tương tự mà cần kiểm tra các tuyến đường (đối với các xung đột với /:slug tuyến đường) và tôi đã kết thúc việc đặt reload_routes! và kiểm tra trong config.after_initialize như bạn đang làm.

+0

Ý tưởng tuyệt vời! Hóa ra chúng ta đang sử dụng điều này cho cùng một điều (tôi đang cập nhật một 'class_attribute' được gọi là' User.invalid_usernames' được sử dụng như một danh sách loại trừ với 'validates_exclusion_of'). Tôi nghĩ rằng tôi vẫn cần to_prepare cho chế độ phát triển mặc dù. Nếu không có nó, nó hoạt động tốt trên yêu cầu đầu tiên (bây giờ tôi đang sử dụng gợi ý của bạn), nhưng sau đó tôi nghĩ rằng 'User.invalid_usernames = Set.new' của tôi là clobbering nó. Nghe có vẻ như bạn đang chỉ sử dụng after_initialize mặc dù, vì vậy tôi tự hỏi nếu có một số cách thông minh bạn có xung quanh đó? – poochenza

+0

Câu trả lời này giúp ích rất nhiều vì vậy tôi chấp nhận nó mặc dù tôi đã không sử dụng nó (mở ra những lời chỉ trích nếu bạn nghĩ mình nên!) Đây là giải pháp đầy đủ của tôi, rất thích phản hồi của bạn nếu bạn có thời gian: http: //stackoverflow.com/a/8713207/1126857 – poochenza

+0

@poochenza: Tôi đã sử dụng 'after_initialize' để đảm bảo không có xung đột mới xuất hiện giữa các bản phát hành: nếu bạn thêm tuyến đường'/pancakes' và xuất bản hai tuần sau đó, bạn muốn biết ai đó đã tạo một người dùng "bánh kếp" trên hệ thống sản xuất trong thời gian đó. Sau đó, tôi so sánh tên người dùng mới với các tuyến đường khi tên người dùng được tạo hoặc cập nhật. –

2

Nếu bạn đang cố gắng để chạy mã trong một initializer sau khi các tuyến đường đã được nạp, bạn có thể thử bằng cách sử dụng tùy chọn after::

initializer "name_of_initializer", after: :add_routing_paths do |app| 
    # do custom logic here 
end 

Bạn có thể tìm thấy sự kiện khởi tạo ở đây: http://guides.rubyonrails.org/configuring.html#initialization-events

+0

Trình khởi tạo này sẽ không bao giờ được thực hiện cho tôi trong đường ray 4.1.14.1 – nolith

Các vấn đề liên quan