Как вызвать повторно используемый код в модели рельсов?

У меня есть повторяющиеся методы в моей модели, и я хочу поместить эти коды в одно место и просто хочу получить к ним доступ в своей модели.

В моей модели есть несколько методов, таких как:

class ProductionProductivity7 < ApplicationRecord
def self.import1(file)
  spreadsheet = Roo::Spreadsheet.open(file.path)
        header = spreadsheet.row(1)
        (2..spreadsheet.last_row).each do |i|
          row = Hash[[header, spreadsheet.row(i)].transpose]
          puts row.to_hash
          product = find_by(id: row["id"]) || new
          product.attributes = row.to_hash
          product.save!
    end
end
def self.search(search,compare)
  if search == "All"
    all.order(:id)
  elsif compare == "Bihar vs District"
    where("Districts = ? OR Districts = ?", search, "Bihar")
  else
    where(Districts: search)
  end
end

конец

Есть еще 3 таких метода, я хочу поместить этот блок кода в помощник и просто хочу вызвать его внутри модели. Для этого я попробовал поместить эти коды в мой помощник. И я вызываю это, используя:

include ApplicationController.ProductionProductivity7sHelper

Я включаю это в свою модель, но получаю эту ошибку:

undefined method `ProductionProductivity7sHelper' for ApplicationController:Class

Мой код контроллера выглядит так:

 def test
      @ProductionProductivity7s = ProductionProductivity7.search(params[:search],compare)
      a = ProductionProductivity7.query(@ProductionProductivity7s,params[:year],rain_fall_type,views,compare)
 end 

Я добавил имя модуля code.rb в папку приложения.

   module Code
    def search(search_scope,compare)
        if search_scope == "All"
        all.order(:id)
        elsif compare == "Bihar vs District"
        where("Districts = ? OR Districts = ?", search_scope, "Bihar")
        else
        where(Districts: search_scope)
        end
    end
end

Я просто хочу написать все свои методы моей модели где-нибудь, это может быть либо модуль, либо помощник, ничего не меняя. Возможно ли, что я просто хочу, чтобы этот блок кода был в моей модели.

Я добавляю весь код контроллера и код модели в gist-файлы. Пожалуйста, посмотрите.Ссылка на мой контроллер и код модели

Я получаю эту ошибку:

 undefined method `search' for #<Class:0x00007ff115974fd8> Did you mean? search1

person Nilay Singh    schedule 06.07.2018    source источник
comment
Как насчет использования сервисов?   -  person jvillian    schedule 06.07.2018
comment
Любой пример вы можете предложить   -  person Nilay Singh    schedule 06.07.2018
comment
Должно быть, это твой старый код, да? Я не вижу extend Code в вашей модели. (Code кажется плохим именем, но я полагаю, вы измените его позже?)   -  person jvillian    schedule 06.07.2018
comment
Обновлен весь предыдущий и новый код по сути   -  person Nilay Singh    schedule 06.07.2018
comment
вы можете просто написать эти методы на своем app/models/application_record.rb и вызвать его из любой модели, как и любые методы экземпляра модели.. плюс у вас будет доступ к self как к любому экземпляру вызывающей модели.   -  person sa77    schedule 07.07.2018


Ответы (2)


Как насчет того, чтобы просто сделать модуль вроде:

module Import1

  def import1(file)
    spreadsheet = Roo::Spreadsheet.open(file.path)
    header = spreadsheet.row(1)
    (2..spreadsheet.last_row).each do |i|
      row = Hash[[header, spreadsheet.row(i)].transpose]
      puts row.to_hash
      product = find_by(id: row["id"]) || new
      product.attributes = row.to_hash
      product.save!
    end
  end

  def search(search_scope,compare)
    if search_scope == "All"
      all.order(:id)
    elsif compare == "Bihar vs District"
      where("Districts = ? OR Districts = ?", search_scope, "Bihar")
    else
      where(Districts: search_scope)
    end
  end

end

Думаю, я бы положил его куда-нибудь в вашу папку app, чтобы у вас не было проблем с автозагрузкой. Вы могли поместить его в корневую папку app, но мне это кажется грязным. Вы также можете поместить его в свою папку models, но тогда у вас будет два совершенно разных вида вещей в одной папке, что также кажется мне беспорядочным. Я думаю, у меня возникнет соблазн создать новую папку, что-то вроде app/model_modules или, возможно, app/shared_model_modules, и поместить туда ваш файл import_1.rb. Тогда понятно, что это за файл.

А затем выполните:

class ProductionProductivity7 < ApplicationRecord
  extend Import1
end

Или как насчет использования службы вместо помощника? ИМО, это делает более явным то, что происходит, тогда как помощники могут запутать, где живет код.

Голые кости BaseService могут выглядеть так:

class BaseService

  attr_accessor :args

  class << self

    def call(args=nil)
      new(args).call
    end

  end # Class Methods

  #=======================================================================
  # Instance Methods
  #=======================================================================

    def initialize(args)
      @args = args || {}
      assign_args
    end

  private

    def assign_args
      args.each do |k,v|
        class_eval do 
          attr_accessor k
        end
        send("#{k}=",v)
      end
    end

end

Тогда ваша служба импорта файлов может выглядеть примерно так:

class ImportFileService < BaseService

  def call
    spreadsheet = Roo::Spreadsheet.open(file.path)
    header = spreadsheet.row(1)
    (2..spreadsheet.last_row).each do |i|
      row = Hash[[header, spreadsheet.row(i)].transpose]
      puts row.to_hash
      product = klass.find_or_initialize_by(id: row["id"])
      product.attributes = row.to_hash
      product.save!
    end
  end

end

И вы бы назвали свою службу примерно так:

ImportFileService.call(file: file, klass: ProductionProductivity7)
person jvillian    schedule 06.07.2018
comment
Мне просто нужен простой ответ. Я обновляю свой вопрос. - person Nilay Singh; 06.07.2018
comment
Это не так сложно. Но я ценю то, что вы говорите. Удачи! - person jvillian; 06.07.2018
comment
Я добавил вызов файла Code.rb в папку приложения, и я добавляю в него все действия моей модели и расширяю модель. Но получаю сообщение об ошибке неопределенный метод `поиск' для #‹Class:0x00007fd13e072288› Я удалил себя, я использую поиск внутри контроллера. - person Nilay Singh; 06.07.2018
comment
Использование search как имени метода, так и имени аргумента может вызывать проблемы (я предположил, но не продумал). Вы можете попробовать изменить аргумент на search_scope, как указано выше. Кроме того, вы, вероятно, захотите следовать соглашениям об именах, чтобы они соответствовали именам ваших файлов и модулей. Если модуль называется FooBar, то и файл должен называться foo_bar.rb. - person jvillian; 06.07.2018
comment
Я изменил свой поиск на search_scope, получая ту же ошибку - person Nilay Singh; 06.07.2018
comment
Это может помочь, если вы отредактируете свой вопрос, чтобы показать текущий код модуля, код вашего контроллера, где вы вызываете search, и ваш стек ошибок. В противном случае немного сложно отладить то, что может произойти. - person jvillian; 06.07.2018
comment
Давайте продолжим это обсуждение в чате. - person Nilay Singh; 06.07.2018

Конечно, вы можете просто создать такой модуль:

module ProductionProductivity7sHelper
  def import1(file) # notice I dropped 'self.'

    ...

  end

  ...

end

Затем в своем классе добавьте:

class ProductionProductivity7 < ApplicationRecord
  extend ProductionProductivity7sHelper

  ...

end

Это добавит все методы, определенные в модуле, в качестве методов класса для ProductionProductivity7. Примечание. Предполагается, что пропущенные вами методы также являются методами класса, т. е. начинаются с «я».

person jesellers    schedule 06.07.2018
comment
Я создал модуль в папке lib с именем code, но получаю ошибку. - person Nilay Singh; 06.07.2018
comment
Я бы просто поместил production_productivity7s_helper.rb в ту же папку, что и другие ваши модели. - person jesellers; 06.07.2018
comment
Кажется, ОП хочет использовать модуль в моделях, отличных от ProductionProductivity7. Я назвал модуль именем метода в первом варианте моего ответа (который совпадает с вашим без имени). - person jvillian; 06.07.2018
comment
Я поместил своего помощника в папку своей модели и удалил себя из действия, но я получаю ошибку неопределенного метода `поиск' для #‹Class:0x00007fd13e072288› Можете ли вы помочь мне с этим, обновив ответ - person Nilay Singh; 06.07.2018
comment
Хм. Можете ли вы запустить консоль rails и посмотреть, распознает ли она ProductionProductivity7.search(search, compare)? - person jesellers; 06.07.2018