我完全重写了这个问题,因为我觉得这更准确地反映了我第一次以较少的迂回方式提出的要求。
在实例化FormObject之后,对动态定义的方法的调用不会在我正在尝试的上下文中评估它们的块参数。例如:
@registration = RegistrationForm.new
@registration.user
# undefined local variable or method `user_params' for RegistrationForm:Class
RegistrationForm调用一个类方法exposing(:user) { User.new(user_params) }
,我想要定义一个如下所示的新方法:
def user
@user ||= User.new(user_params)
end
我的实现不使用@ivar ||=
来缓存值(因为falsey值会导致重新评估该方法)。我从rspec的memoized_helpers中借用了这个想法,我想'我明白它是如何工作的。我不明白的是我应该在class_eval
中替换lib/form_object/memoized_helpers.rb
。
谢谢
LIB / form_object / base.rb
class FormObject::Base
include ActiveModel::Model
include FormObject::MemoizedHelpers
attr_reader :params, :errors
def initialize(params = {})
@params = ActionController::Parameters.new(params)
@errors = ActiveModel::Errors.new(self)
end
def save
valid? && persist
end
end
LIB / form_object / memoized_helpers.rb
module FormObject
module MemoizedHelpers
private
def __memoized
@__memoized ||= {}
end
def self.included(mod)
mod.extend(ClassMethods)
end
module ClassMethods
def exposing(name, &block)
raise "#exposing called without a block" unless block_given?
class_eval do
define_method(name) { __memoized.fetch(name) { |k| __memoized[k] = block.call } }
end
end
end
end
end
应用/形式/ registration_form.rb
class RegistrationForm < FormObject::Base
exposing(:user) { User.new(user_params) { |u| u.is_admin = true } }
exposing(:tenant) { user.build_tenant(tenant_params) }
validate do
tenant.errors.each do |key, value|
errors.add("#{tenant.class.name.underscore}_#{key}", value)
end unless tenant.valid?
end
validate do
user.errors.each do |key, value|
errors.add("#{user.class.name.underscore}_#{key}", value)
end unless user.valid?
end
private
def persist
user.save
end
def user_params
params.fetch(:user, {}).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
def tenant_params
params.fetch(:tenant, {}).permit(:name)
end
end
答案 0 :(得分:1)
所以,我可能过多地简化了这个例子,但我认为这就是你想要的:
module Exposing
def exposing(name, &block)
instance_eval do
define_method(name, block)
end
end
end
class Form
extend Exposing
exposing(:user) { user_params }
def user_params
{:hi => 'ho'}
end
end
Form.new.user
你可以在这里摆弄:http://repl.it/OCa