Creators help to clean up your controllers from the model creation setup code. For the most basic situations simply creating a Creator and passing into it the request params, will just work for creating a new model, and if you'll require adding custom validations, slicing up garbage params or refining a new Hash of params to be used for the Model attributes, then a Creator is the home for all that.
Just add the creators gem to your Gemfile
gem 'creators'
This example shows a very simple happy-sad flow for creating a project model using a creator. You can access the newly created project model when the creation is successful or the errors array if it's not.
class ProjectsController < ApplicationController
def create
project_creator = ProjectCreator.new(params, current_user)
if project_creator.save
redirect_to project_url(project_creator.project)
else
logger.fatal "Could not create project. Error list: #{project_creator.errors.join(", "}")
redirect_to error_page_url
end
end
end
We recommend putting all your creator objects in app/creators
.
The model class that's attached to the creator is deduced from the name of the class.
You can override this behavior by adding a model
definition to the creator (model 'AnotherModel'
).
class ProjectCreator < Creators::Base
def initialize(raw_params, current_user)
@user = current_user
super(raw_params)
end
def before_build # optional
error("project", "must be an hash") unless @params[:project].is_a? Hash
end
def refine_params # optional
@params[:project]
end
def after_build # optional
project.members.build(refined_admin)
end
private
def refined_admin
{
:role => :admin,
:name => @user.name
}
end
end
A Creator simply requires the raw_params
from the request,
you can also add any other data that you might need.
For example in the ProjectsCreator we need the current_user.
The specific behavior of your Creator is defined in the refine_params
method and the callback methods, that compose
the Save method Life Cycle. The Creator save
method is divided into 2 main steps:
-
build
- This step simply instantiates a new model (Project in our example) and assigns to it theraw_params
we've passed to the Creator. Therefine_params
step by default just uses theraw_params
, and it can be easily overridden by using therefine_params
method. (As shown in our example) Callback methods:before_build
,after_build
-
save
- Simply calls@model.save
. Callback methods:before_save
,after_save
|-- Save Life Cycle
|--|-- before_build
|--|-- refine_params
|--|-- after_build
|--|-- before_save
|--|-- after_save
Here's an example for a creator for the Task model, it relates to the Project model with a belongs_to association.
class TasksController < ApplicationController
def update
current_task = current_project.tasks.find_by_id(params[:task][:id])
task_creator = TaskCreator.new(params, current_task)
if task_creator.save
render :json => task_creator.task
else
logger.fatal "Could not update task for project #{current_project.id}. Error list: #{task_creator.errors.join(", "}")
end
end
end
class TaskCreator < Creators::Base
def initialize(raw_params, current_task)
@task = task
super(raw_params, @task)
end
def refine_params
params[:task]
end
end
For update operations, if you pass to super a model as the 2nd argument, then that model will be used in the build process instead of it creating a new one, in case that model isn't nil.
Ruby 1.8.7+, Rails 3.0+.