Design rubies on rails
Sorry in advance for the long post. I've been working in Ruby on Rails for about 6 months and am trying to apply design patterns from java / C # to problems in RoR. I feel like there are better ways to do the same in RoR, but unfortunately I'm just a noob. So here is one of the main problems I am trying to find a Ruby oriented pattern for. Any guidance would be much appreciated.
There is a lot of "common" behavior in my application controllers. In many cases, there is controller-specific initialization (i.e. setting the user_id attribute of the object for the current user, filtering the write-once attributes) and authorizing actions based on the object instance and the current user. Thus, many models and controllers look something like this:
class Object < ActiveRecord::Base
...
def authorize_action(user, action)
[:show,:create].include?(action) || self.created_by_user_id == user.id # only the user who created can update/delete
end
def init_new(signed_in_user)
self.created_by_user_id = signed_in_user.id
if self.location_id.nil?
self.location_id = signed_in_user.default_location_id
end
end
end
ObjectController < ApplicationController
before_action :set_object, only: [:show, :edit, :update, :destroy]
before_action :authorize_action, only: [:show, :edit, :update, :destroy]
...
def new
@object = Object.new
@object.parent_id = params[:parent_id] # nested resource, assign parent_id from request url
@object.created_by_user_id = current_user.id
end
def edit
end
def create
@object = Object.new(object_create_params)
@object.parent_id = params[:parent_id] # nested resource, assign parent_id from request url
@object.created_by_user_id = current_user.id
@object.save
end
def update
@hunting_plot_user_access.update(object_update_params)
end
def destroy
@object.destroy
end
private
set_object
@object = Object.find(params[:id])
end
def object_create_params
params.require(:object).permit(:location_id, :attribute_1, :attribute_2)
end
def object_update_params
params.require(:object).permit(:attribute_1, :attribute_2)
end
def authorize_action
raise Exceptions::NotAuthorized unless @object.authorize_action?(current_user, action_name)
end
end
I would like to move the general "flow" of each general activity into the general logic. For example, to create a new instance of any given object, the controller must instantiate, call the init_new method on the instance (all models have this method), potentially use controller-specific changes, allow the action, and save the object to the instance.
I must think this is a fairly common design problem. I am kicking solutions that use a combination of adding "virtual" methods and custom callbacks to the ApplicationController class, but it seems to me that I am trying to set a square snap to a round hole.
Does anyone have any suggested articles, blog posts, etc. that might solve the same problem?
source to share
Inheritance is one way:
class BaseController < ApplicationController
before_filter :some_common_thing
def some_common_thing
# common code
end
end
class ObjectController < BaseController
# just the code that is unique to this controller
end
... with the caveat that you don't go too far - here is a good article on inheritance in ruby (although it applies to any OO language)
source to share