简体   繁体   中英

ruby on rails design patterns

Sorry in advance for the long post. I have been working in Ruby on Rails for about 6 months now and find myself trying to apply design patterns from java/C# to problems in RoR. I feel like there are better ways to do the same things in RoR, but sadly I am just a noob. So here is one basic problem for which I am trying to find a Ruby-oriented design pattern. Any guidance would be much appreciated.

Within my app's controllers, there is a lot of 'shared' behavior. In many cases there is controller-specific initialization (ie, setting the object's user_id attribute to the current user, filtering out write-once attributes) and authorizing actions based on the object instance and the current user. So, many models and controllers look similar to 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'd like to move the general 'flow' of each common action into shared logic. For example, to create a new instance of any given Object, a controller should create the instance, call the init_new method on the instance (all models have this method), potentially apply controller-specific changes, authorize the action, and save the object instance.

I've to think this is a fairly common design problem out there. I have been kicking around solutions that use a combination of adding 'virtual' methods and custom callbacks to the ApplicationController class, but it feels like I am trying to fit a square peg into a round hole.

Anyone out there have any suggested articles, blog posts, etc that might address the same issue?

Inheritance is one way to go:

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's a good article about inheritance in ruby (although it's applicable to any OO language)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM