Implementing Form Objects in Hanami - hanami

In Uncle Bob's clean architecture, which Hanami is inspired by, Form Objects guard the boundary between Interactors and our delivery mechanism (typically an http endpoint).
In the Hanami docs, bounary guarding is done using params blocks in Actions (see here). This seems to couple validation to the http delivery mechanism. It seems more natural to me that Form Objects (or params black which accomplish the same thing) would live in delivery-mechanism-agnostic Interactors.
Unfortunately, I cannot figure out if Hanami supports such a design. I found a similar question on the Hanami forum, but it has no answer.
To clarify, below is a snippet of code demonstrating the kind of thing I want to do, but using Virtus and ActiveModel::Validations rather than Hanami facilities. For those familiar with Trailblazer, its contract block within its operations (its term for Interactor) is another example.
Finally, am I misunderstanding something about the intended use of Hanami? Hanami supports Interactors, so it seems like this should be possible...
require 'hanami/model'
require 'active_model'
require 'virtus'
class PersonForm
include Virtus.model
include ActiveModel::Validations
attribute :name, String
attribute :age, Integer
validates :name, :age, presence: true
def each
attributes.each {|a| yield a}
end
end
class Person
include Hanami::Entity
attributes :name, :age
end
# Code like this would then live inside of an Interactor, which
# can accept a params hash.
jonah_form = PersonForm.new({name: 'Jonah', age: '99'})
jonah = Person.new(jonah_form) if jonah_form.valid?
p jonah #=> <Person:0x007fbdde1edcc0 #id=nil #name="Jonah" #age=99>
# do stuff with our jonah entity

sorry for missing this question.
The params act as validator to save developers to create and instantiate another class. In Ruby Community this is a problem.
DSL to the rescue for this compromise.
If you prefer to have a concrete form object, instead of using Virtus and ActiveModel, you can just include Hanami::Validations and have the same behavior.

Related

Why is Model.associations an Array, but still supports sql queries? [duplicate]

In Rails, I have created a Model that retrieves users from an LDAP database rather than from ActiveRecord. Now I am attempting to integrate my ActiveRecord models with the LDAP-based models, so I am writing methods in my models that emulate some common ActiveRecord methods.
One of the methods I am trying to emulate is one that is normally created by the has_many through relationship on ActiveRecord. In ActiveRecord, this relationship would allow the following:
user = User.first
groups = user.groups # == Array of Groups
groups << Group.create(name: "Test") # How does Rails allow this?
How exactly does Rails allow this? I've tried dynamically assigning methods to the array instance returned by user.groups, but there doesn't seem to be any way to make those methods aware of which user record the array was created from. (So they can assign user_id on the new relationship record.) What am I missing?
Though user.groups appears to be an array of groups, it's actually an entirely separate class -- a Rails internal class that you usually don't know much about called an association proxy. The proxy responds to methods like <<, create, new and so on by proxying requests to the target class and then setting the association appropriately.
If you want similar functionality you'll have to implement your own kind of proxy associations. Doing so will be pretty complicated, but this might get you started.
module LDAP
class Association
attr_accessor :source, :target
def initialize(source, target)
#source = source
#target = target
end
def <<(obj)
#source.group_ids = [group_ids + obj].flatten.uniq
#source.save
end
end
end
class User
def groups
LDAP::Association.new(self, Group)
end
end
This is not even particularly close to how ActiveRecord implements association proxies. However, this is quite a bit simpler than ActiveRecord's solution and should be enough to duplicate some basic ActiveRecord functionality.
I would go about doing this by peeking into the Rails Source Code, e.g. the code for the
Group.create example above can be found in
http://api.rubyonrails.org/classes/ActiveRecord/Persistence/ClassMethods.html
def create(attributes = nil, options = {}, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, options, &block) }
else
object = new(attributes, options, &block)
object.save
object
end
end
end

Rails + Devise - Session Controller explaination

I am playing around with Devise in a project, and am just trying to better understand how it all works. The Sessions controller in particular is doing a few things that I don't understand:
class Devise::SessionsController < ApplicationController
def new
# What benefit is this providing over just "resource_class.new"?
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
# What is "serialize_options" doing in the responder?
respond_with(resource, serialize_options(resource))
end
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
...
protected
...
def serialize_options(resource)
methods = resource_class.authentication_keys.dup
methods = methods.keys if methods.is_a?(Hash)
methods << :password if resource.respond_to?(:password)
{ :methods => methods, :only => [:password] }
end
def sign_in_params
devise_parameter_sanitizer.sanitize(:sign_in)
end
end
I assume that these methods are adding some sort of security. I'd just like to know what exactly they are protecting against.
The implementation of devise_parameter_sanitizer is creating a ParameterSanitizer instance. I often find looking at tests to be helpful in understanding the purpose of code; and this test I think illustrates it best-- since you're creating a new user, you don't want to allow users to assign any value they want to any parameter they want, so sanitize means "strip out any attributes other than the ones we need for this action". If this wasn't here, and you had a role attribute, a user could send a specially-crafted POST request to make themselves an admin when signing up for your site. So this protects against what's called, in the general case, a mass assignment vulnerability. Rails 3 and Rails 4 protect against this in different ways but the protections can still be turned off, and I'm guessing Devise is trying to set some good-practice defaults.
The serialize_options method is creating a hash of options to support rendering to XML or JSON. I found this out by looking at the implementation of responds_with, which calls extract_options! which uses the last argument as options if the last argument is a Hash. The documentation for responds_with says "All options given to #respond_with are sent to the underlying responder", so I looked at ActionController::Responder, whose documentation explains the process it takes to look for a template that matches the format, then if that isn't found, calling to_#{format}, then calling to_format. There's a view for HTML, and ActiveRecord objects respond to to_xml and to_json. Those methods use those options:
The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the
attributes included, and work similar to the +attributes+ method.
To include the result of some method calls on the model use <tt>:methods</tt>.
So this keeps you from exposing more information than you might want to if someone uses the XML or JSON format.

What is mass-assignment in Rails 3

I have heard couple of people complaining and posting questions about mass-assignment in Rails. I have got same error couple of times and all I did was attr_accessible. But what exactly is mass assignment? could somebody explain with example?
Mass Assignment is the name Rails gives to the act of constructing your object with a parameters hash. It is "mass assignment" in that you are assigning multiple values to attributes via a single assignment operator.
The following snippets perform mass assignment of the name and topic attribute of the Post model:
Post.new(:name => "John", :topic => "Something")
Post.create(:name => "John", :topic => "Something")
Post.update_attributes(:name => "John", :topic => "Something")
In order for this to work, your model must allow mass assignments for each attribute in the hash you're passing in.
There are two situations in which this will fail:
You have an attr_accessible declaration which does not include :name
You have an attr_protected which does include :name
It recently became the default that attributes had to be manually white-listed via a attr_accessible in order for mass assignment to succeed. Prior to this, the default was for attributes to be assignable unless they were explicitly black-listed attr_protected or any other attribute was white-listed with attr_acessible.
It is important to consider which attributes can be mass assigned because code like this is so common:
#post = Post.new(params[:post])
Typically this is used when the user submits a form rendered by a form_for #post. In an ideal world, the params[:post] hash should only contain the fields we displayed on the form. However, it is trivial easy for the user to pass additional fields in their request, so in effect you're allowing a user to set any fields on #post, not just the ones displayed on the form.
Failure to safely use mass assignment has led to several high profile bugs in some pretty big Rails applications, like the one that allowed somebody to inject their own public key into the list of trusted keys on a Github repository and push code directly to a repository they should not have had access to.

Unclear when to use a specific FactoryGirl syntax

In the latest release of FactoryGirl, some syntactic methods such as Factory.create were depreciated in favor of several others, most notably FactoryGirl.create and the simpler create.
However, experience shows that certain syntaxes are not always appropriate given the context.
Take for example:
FactoryGirl.define do
factory :article do
after_create {|a| a.comments << create(:comment) }
end
factory :comment do
end
end
Where Article has_many Comments, and Comments belongs_to Article. In the above factories, a.comments << create(:comment) issues the error Comment(#nnn) expected, got FactoryGirl::Declaration::Static. Change that line to a.comments << FactoryGirl.create(:comment) and the error goes away.
It is not clear when one syntax should take precedence over any other form.
I learned the abbreviated notation is not supported in callbacks (such as after_create) as of the current version (3.2.0). This information came directly from the FactoryGirl teams via Google groups. I'll update this question when/if it's added in a future version.
As per the FactoryGirl documentation, if you want to omit the FactoryGirl module prefix while calling methods like create and build, you need to mix-in FactoryGirl methods in rspec/test-unit module like this:
# rspec
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end

avoiding code duplication in Rails 3 models

I'm working on a Rails 3.1 application where there are a number of different enum-like models that are stored in the database. There is a lot of identical code in these models, as well as in the associated controllers and views. I've solved the code duplication for the controllers and views via a shared parent controller class and the new view/layout inheritance that's part of Rails 3.
Now I'm trying to solve the code duplication in the models, and I'm stuck. An example of one of my enum models is as follows:
class Format < ActiveRecord::Base
has_and_belongs_to_many :videos
attr_accessible :name
validates :name, presence: true, length: { maximum: 20 }
before_destroy :verify_no_linked_videos
def verify_no_linked_videos
unless self.videos.empty?
self.errors[:base] << "Couldn't delete format with associated videos."
raise ActiveRecord::RecordInvalid.new self
end
end
end
I have four or five other classes with nearly identical code (the association declaration being the only difference). I've tried creating a module with the shared code that they all include (which seems like the Ruby Way), but much of the duplicate code relies on ActiveRecord, so the methods I'm trying to use in the module (validate, attr_accessible, etc.) aren't available. I know about ActiveModel, but that doesn't get me all the way there.
I've also tried creating a common, non-persistent parent class that subclasses ActiveRecord::Base, but all of the code I've seen to accomplish this assumes that you won't have subclasses of your non-persistent class that do persist.
Any suggestions for how best to avoid duplicating these identical lines of code across many different enum models?
I found a solution to the code sharing for Rails 3 models, so thought I'd share it with others. It turns out ActiveModel does have everything I need (so far, at least). I created an Enum module using ActiveSupport::Concern, ActiveModel::Validations, and ActiveModel::MassAssignmentSecurity, and I include the module in each of my enum models:
module Enum
extend ActiveSupport::Concern
include ActiveModel::Validations
include ActiveModel::MassAssignmentSecurity
included do
attr_accessible :name
validates :name, presence: true, length: { maximum: 20 }
before_destroy :verify_no_linked_videos
private
def verify_no_linked_videos
unless self.videos.empty?
self.errors[:base] << "Couldn't delete object with associated videos."
raise ActiveRecord::RecordInvalid.new self
end
end
end
end
The way the Rails 3 team pulled out the non-database code from ActiveRecord into ActiveModel really is pretty slick! The following links helped solidify my understanding of how to use this stuff:
http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active-support-concern/
http://asciicasts.com/episodes/237-dynamic-attr-accessible