Example of generalization Question

I'm new to Ruby on Rails and as a C # developer, when I want to reuse code (for a repository class), I could put it in a base class like <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 know that you can do this:

 class UsersController < ApplicationController 

This will allow access to all methods in the ApplicationController and parent classes. When using linings, 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 

As a result, I have 10 classes that have the same method, but the only difference is "User.all", "Post.all", etc.

How do I make this method generic so that I can put it in the ApplicationController class?

Thanks for any help you can provide to newbies to Ruby on Rails.

+4
source share
5 answers

The first thing you need to understand about the forest code is its abbreviation:

 def index @users = User.all end 

if you do not intend to deliver the presentation in a different format, for example json, html, pdf, the reply_to block is not needed. If you still feel the need to dry this method, you can 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 how

 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 
+4
source

Instead of doing eval , where you really don't want to do this. Check out Jose Valim's Inherited Gem Resources . It provides standard CRUD methods for all of your controllers and is quite sophisticated. It has also been thoroughly tested, so you donโ€™t have to worry about making your generic code function as expected in all cases.

For more information on how to use it, see the linked GitHub page.

+3
source

Perhaps a simple solution might be to use mixins.

You define a module,

 module MyModule def my_index(klass) @elements = klass.all respond_to do |format| format.html # index.html.erb format.xml { render :xml => @elements } end end end 

Then you have in your controller

 include MyModule def index my_index(User) end 

Of course you need to use @elements in your views. If you want to have a different variable name in each view, you can do

  def my_index(klass, var_name) self.instance_variable_set(var_name, klass.all) ... end 
+3
source

There are several rail plugins that help reduce this type of duplication. This was described in episode 230 of railscast.

https://github.com/josevalim/inherited_resources

+1
source
  • Based on my experience, you rarely @user = User.all up in 10 index actions similar to @user = User.all . If you know in advance that some actions between different models will be the same, then it may be wise to extract common logic. But then again, perhaps these models are somehow connected? I would not say in advance that Post and User will have the same index actions.
  • For a short method like this, I would not try to repeat the repetition, because you might lose readability.
0
source

Source: https://habr.com/ru/post/1339484/


All Articles