Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics Example Question

I am fairly new to Ruby on Rails and as a C# developer, when I want to re-use code (for a repository class), I could put it into a base class of type <T> to be able to do something like this:

public virtual IEnumerable<T> GetAll()
{
    return Context<T>.GetAll();
}

If I need to do any custom logic, I could, of course, override the method in my 'User' repository.

In Ruby, I am familiar that you can do this:

class UsersController < ApplicationController

This will allow access to all methods in ApplicationController and it's parent classes. When using scaffolding, it generates the following method in each of my child classes:

def index
  @users = User.all

  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @users }
  end
end

What I end up with is 10 classes that have the same method, but the only difference is 'User.all', 'Post.all', etc.

How would I make this method generic so I can put it in my ApplicationController class?

Thanks for any assistance you can provide to a Ruby on Rails newbie.

like image 865
Brandon Avatar asked Dec 21 '22 17:12

Brandon


2 Answers

The first thing to realize about the scaffolding code is that it can be abreviated, as such:

def index
  @users = User.all
end

unless you intend to deliver the view in another format, like json, html, pdf, the respond_to block is unnecessary. If you still feel the need to dry up this method, you could do something like

# app/controllers/concerns/autoload_records.rb

module AutoloadRecords
  included do
    before_action :load_records, only: :index
    before_action :load_record, only: [:create, :show, :edit, :update, :destroy]
  end

  private
  def load_records
    @records = model_class.all
  end

  def load_record
    @record = model_class.find(params[:id])
  end

  def model_class
    klass = self.class.to_s[/\A(\w+)sController\Z/,1] #=> get the name of the class from the controller Constant
    Object.const_get(klass)
  end
end

and write your controller like

class UsersController < ApplicationController
  include AutoloadRecords

  def index
    @records # => #<ActiveRecord::Relation[...]>
  end

  def show
    @record # => #<User ...>
  end

  def non_rest_action
    @record # => nil
    @records # => nil
  end
end
like image 132
Jed Schneider Avatar answered Jan 09 '23 07:01

Jed Schneider


Rather than doing an eval where you really don't want to be doing one. Check out Jose Valim's Inherited Resources gem. It provides the standard CRUD methods for all of your controllers and is quite sophisticated. It is also thoroughly tested so you don't have to worry about making sure your generic code operates as expected in all cases.

For details on how to use it see the GitHub page linked.

like image 31
nuclearsandwich Avatar answered Jan 09 '23 06:01

nuclearsandwich