如何在Rails Seeds中复用RSpec中定义的AuthorizationHelpers模块方法?
要把RSpec里的AuthorizationHelpers模块用到Seeds里其实很简单,核心就是让模块能被Rails的Seeds脚本加载到,我给你一步步拆解实现步骤:
1. 把模块移到共享位置(lib目录)
别再把模块只放在RSpec专属的spec/support目录里了,把它迁移到项目根目录的lib文件夹下,创建lib/authorization_helpers.rb文件,内容保留你的原模块代码:
module AuthorizationHelpers def assign_role!(user, role, post) Role.where(user: user, post: post).delete_all Role.create!(user: user, role: role, post: post) end end
2. 让Rails能加载这个模块
Rails默认不会自动加载lib目录下的文件,你可以选下面两种方式之一解决:
方式A:配置全局自动加载(推荐)
打开config/application.rb,在class Application < Rails::Application代码块里添加一行:
config.autoload_paths << Rails.root.join('lib')
这样Rails启动时会自动加载lib目录下的所有文件,不管是Seeds还是RSpec都能直接找到这个模块。
方式B:在Seeds里手动引入
如果不想修改全局配置,就在db/seeds.rb的最开头添加手动引入代码:
require_relative '../lib/authorization_helpers'
3. 在Seeds里调用方法
现在有两种调用方式,选你习惯的就行:
方式1:include模块后直接调用
在db/seeds.rb开头加上include语句,之后就能像你示例里那样直接用assign_role!:
include AuthorizationHelpers Post.all.each do |post| [:manager, :editor, :viewer].each do |role| User.all.where(admin: false).each do |user| assign_role!(user, role, post) end end end
方式2:用模块名直接调用(不污染全局上下文)
如果你不想把方法加到全局的main对象里,可以给模块添加模块方法支持:
修改lib/authorization_helpers.rb,加上module_function:
module AuthorizationHelpers def assign_role!(user, role, post) Role.where(user: user, post: post).delete_all Role.create!(user: user, role: role, post: post) end # 把方法转为模块方法,同时保留实例方法(方便RSpec include使用) module_function :assign_role! end
然后在Seeds里直接通过模块名调用:
Post.all.each do |post| [:manager, :editor, :viewer].each do |role| User.all.where(admin: false).each do |user| AuthorizationHelpers.assign_role!(user, role, post) end end end
4. 调整RSpec的配置(可选)
因为模块现在在lib目录,RSpec那边的配置可以稍作调整确保加载:
打开spec/spec_helper.rb或者spec/rails_helper.rb,原来的配置可以改成:
# 如果已经配置了全局autoload_paths,这行require可以省略 require_relative '../../lib/authorization_helpers' RSpec.configure do |c| c.include AuthorizationHelpers end
要是已经在application.rb里配置了autoload_paths,RSpec启动时会自动加载模块,这行require就不用加了。
这样不管是RSpec测试还是Seeds脚本,都能复用这个assign_role!方法啦!
内容的提问来源于stack exchange,提问作者rld

