-
-
Save frankjmattia/0096f7436a14d95b5ed9 to your computer and use it in GitHub Desktop.
MemoizedHelpers is based on the implementation of #let in Rspec found here: https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/memoized_helpers.rb. When I run this I get NoMethodError super: no superclass method `tenant' for #<RegistrationForm:0x007fb25f0c3a78> at Line 28 of memoized_helpers.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class FormObject::Base | |
include ActiveModel::Model | |
include 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module FormObject | |
module MemoizedHelpers | |
private | |
def __memoized | |
@__memoized ||= {} | |
end | |
def self.included(mod) | |
mod.extend(ClassMethods) | |
end | |
def self.definitions_module_for(form_object) | |
if form_object.const_defined?(:ModelDefinitions, false) | |
form_object.const_get(:ModelDefinitions, false) | |
else | |
form_object.const_set(:ModelDefinitions, Module.new) | |
end | |
end | |
module ClassMethods | |
def exposing(name, &block) | |
raise "#exposing called without a block" unless block_given? | |
MemoizedHelpers.definitions_module_for(self).send(:define_method, name, &block) | |
# If the exposing block has a parameter set it to the FormObject instance. I'd | |
# rather not do this at all and just always execute in the correct context. | |
# eg: remove the block.arity conditional and just expect arity to be 0. | |
if block.arity == 1 | |
define_method(name) { __memoized.fetch(name) { |k| __memoized[k] = super(self, &nil) } } | |
else | |
define_method(name) { __memoized.fetch(name) { |k| __memoized[k] = super(&nil) } } | |
end | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class RegistrationForm < FormObject::Base | |
# Instead of having to specify |form_instance| I would like the block | |
# to be automatically executed in the context of the form_instance | |
# so I can do something like User.new(user_params) instead of form_instance.user_params | |
exposing(:user) { |form_instance| User.new(form_instance.user_params) { |u| u.is_admin = true } } | |
exposing(:tenant) { |form_instance| user.build_tenant(form_instance.tenant_params) } | |
# Ultimately, the #expsosing calls will dynamically create these validate blocks | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment