Rails 3 Concert Modules for Models

First, I follow the practice found here for Rails issues (great idea!): Https://gist.github.com/1014971

I get an error message:

undefined method `search' for #<Class:0x5c25ea0> app/controllers/accessories_controller.rb:6:in `index' 

I DO have a directory / app / models / concerns / directory loaded in /config/application.rb. In this way, the worry modules are loaded. Just wanted to point it out.

Here is my code:

/app/models/concerns/searchable.rb

 module Searchable extend ActiveSupport::Concern # Add a "search" scope to the models def self.search (search) if search where('name LIKE ?', "%#{search}%") else scoped end end end 

/app/models/accessory.rb

 class Accessory < ActiveRecord::Base include Searchable ... end 

/app/controllers/accessories_controller.rb

 class AccessoriesController < ApplicationController def index @accessories = Accessory.search(params[:search]) ... end end 
+6
source share
3 answers

Well, having some fun, I realized what was wrong!

If you want to directly modify the model from the module (problem), you need to wrap the functionality inside the block .

I changed my support module to the following:

  module Searchable extend ActiveSupport::Concern included do # Add a "search" scope to the models def self.search (search) if search where('name LIKE ?', "%#{search}%") else scoped end end end end 

That's all! Hope this helps someone else with the same question!

+8
source

This is a worthy solution, but not the best solution. When you create a module on ActiveSupport::Concern , you can wrap a module called ClassMethods inside your problem, and any module that includes your problem will be automatically expanded using the ClassMethods module.

Then the best solution would be:

 module Searchable extend ActiveSupport::Concern module ClassMethods def search(search) if search where('name LIKE ?', "%#{search}%") else scoped end end end end 

This (IMO) more clearly expresses your intention: placing a class of a class in a class.

While your approach works, the included method is best used when you need to call methods in the calling class. For example, you can insist that your Searchable objects have a name attribute with db support, as shown below. The method included adding validator presence to the calling class, and the methods that you use to extend the class, separated clearly.

 module Searchable extend ActiveSupport::Concern def self.included(base) base.send :validates_presence_of, :name end module ClassMethods def search(search) if search where('name LIKE ?', "%#{search}%") else scoped end end end end 
+8
source

As AndyV points out , the correct solution is the following:

 module Searchable extend ActiveSupport::Concern module ClassMethods def search(search) if search where('name LIKE ?', "%#{search}%") else scoped end end end end 

And without defining self.search in the included block, as you do in your decision, which is more detailed and less explicit.

But I do not agree with AndyV in using self.included . If you use ActiveSupport::Concern to have syntactic sugar included , so you should use it. I rely only on self.included when the order of the methods that I call or the methods that I define are relevant.

+2
source

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


All Articles