Ruby on Rails中如何在非控制器类中获取请求参数?
解决非控制器类无法访问Rails params的问题
核心原因
Rails的params是控制器特有的请求上下文对象,非控制器类本身没有这个对象,直接调用会报错;而直接调用控制器方法时,由于未初始化控制器的请求上下文实例,params内部依赖的对象为nil,触发undefined method 'filtered_parameters' for nil:NilClass错误。
正确解决方案
方案1:显式传递参数(推荐)
这是最符合解耦设计的方式,把需要的参数直接传给非控制器类的方法:
- 修改非控制器类的
request方法,增加station_id参数:
def self.request(req_num, time, station_id) token = XsrfToken.last['token'] db_parser = FetchDbParser.new used_url = ENUM_URLS[req_num] p token conn = Faraday.new( url: "#{BASE}#{used_url}", headers: { 'Content-Type' => 'application/json', 'XSRF-TOKEN' => token } ) response = conn.post do |req| req.body = { stationCodes: station_id, collectTime: time }.to_json end res = JSON.parse(response.body) return unless res['success'] parser_caller(req_num, res, db_parser) end
- 在控制器中调用该方法时,传入
params[:id]:
YourNonControllerClass.request(req_num, time, params[:id])
这种方式让非控制器类不依赖请求上下文,保持独立性,也更易于测试。
方案2:通过Thread传递请求上下文(不推荐)
如果必须在非控制器类中获取请求上下文,可通过线程局部变量传递,但存在线程安全风险:
- 在
ApplicationController中添加钩子,将请求对象存入线程:
class ApplicationController < ActionController::Base before_action do Thread.current[:current_request] = request end after_action do Thread.current[:current_request] = nil # 清理避免线程污染 end end
- 在非控制器类中获取参数:
def self.request(req_num, time) request = Thread.current[:current_request] station_id = request.params[:id] # 后续原有代码,将params[:id]替换为station_id token = XsrfToken.last['token'] db_parser = FetchDbParser.new used_url = ENUM_URLS[req_num] p token conn = Faraday.new( url: "#{BASE}#{used_url}", headers: { 'Content-Type' => 'application/json', 'XSRF-TOKEN' => token } ) response = conn.post do |req| req.body = { stationCodes: station_id, collectTime: time }.to_json end res = JSON.parse(response.body) return unless res['success'] parser_caller(req_num, res, db_parser) end
注意:这种方式会让非控制器类与请求上下文强耦合,不利于复用和测试,仅在特殊场景下使用。
为什么之前的方法报错
你尝试调用ApplicationController的方法时,控制器的params方法依赖于控制器实例的请求上下文(比如@_request对象),直接调用类方法或未正确初始化控制器实例时,这些依赖对象为nil,因此触发filtered_parameters未定义的错误。
内容的提问来源于stack exchange,提问作者d1msk1y
相关产品推荐
相关产品推荐

