0

I have a repeated methods in my model and I want to put those codes into one place and just want to access it into my model.

My model have few methods such as:

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

end

There are 3 more methods like this , I want to put this code block into helper and just want to call it inside model. For that I have tried this put these codes into my helper. And I am calling it using:

include ApplicationController.ProductionProductivity7sHelper

I am including this inside my model but I am getting this error:

undefined method `ProductionProductivity7sHelper' for ApplicationController:Class

My controller code is like this:

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

I have added a module name code.rb in app folder.

   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

I just want to write all of my methods of my model somewhere it can be either module or helper without changing anything. Is it possible I just want this code block in my model.

I am adding whole controller code and model code in gist files. Please have a look. My controller and Model code link

I am getting this error:

 undefined method `search' for #<Class:0x00007ff115974fd8> Did you mean? search1
5
  • How about using services instead? Commented Jul 6, 2018 at 16:03
  • Any example you can suggest Commented Jul 6, 2018 at 16:04
  • That must be your old code, yes? I don't see extend Code in your model. (Code seems like a bad name, but I assume you'll change that later?) Commented Jul 6, 2018 at 17:25
  • Updated whole previous and new code on gist Commented Jul 6, 2018 at 17:32
  • you can just write those methods on your app/models/application_record.rb and call it from any model like any model instance methods .. plus you'll have access to self as any of your calling model's instance Commented Jul 6, 2018 at 21:04

2 Answers 2

2

How about just making a module like:

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

I think I would put it somewhere in your app folder so that you don't have problems with autoloading. You could put it in your root app folder, but that seems messy to me. You could also put it in your models folder, but then you have two very different kinds of things in the same folder which also seems messy to me. I think I would be tempted to create a new folder, something like app/model_modules or perhaps app/shared_model_modules and put your import_1.rb file in there. Then, it's clear what the file is.

And then do:

class ProductionProductivity7 < ApplicationRecord
  extend Import1
end

Or, how about using a service instead of a helper? IMO, it makes it more explicit what is going on whereas helpers can obsfucate where code lives.

A bare bones BaseService might look like:

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

Then, your file import service might look something like:

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

And you would call your service something like:

ImportFileService.call(file: file, klass: ProductionProductivity7)
Sign up to request clarification or add additional context in comments.

7 Comments

I just want a simple answer I am updating my question
It's not that complicated. But, I appreciate what you are saying. Best of luck!
I added a file call Code.rb inside app folder and I am adding all of my model's action into it and extending in model. But getting error error undefined method `search' for #<Class:0x00007fd13e072288> I removed self I am using search inside controller.
The use of search as both a method name and an argument name might be causing problems (I'm speculating and haven't thought it through). You might try changing the argument to search_scope, as above. Also, you probably want to following naming conventions to match your file and module names. If the module is called FooBar, then the file should be called foo_bar.rb.
It might help if you edit your question to show your current module code, your controller code where you are calling search, and your error stack. Otherwise, it's a little difficult to debug what might be happening.
|
0

Sure, can you just create a module like so:

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

    ...

  end

  ...

end

Then in your class, add:

class ProductionProductivity7 < ApplicationRecord
  extend ProductionProductivity7sHelper

  ...

end

This will add all the methods defined in the module as class methods for ProductionProductivity7. Note: This assumes that the methods you omitted are also class methods, i.e., begin with 'self.'

5 Comments

I created a module in lib folder called code but getting error.
I would just put production_productivity7s_helper.rb in the same folder as your other models.
It seems the OP wants to use the module in models other than ProductionProductivity7. I named the module as the method name in the first option of my answer (which is the same as yours sans naming).
I put my helper in my model folder and removed self from action but I am getting error undefined method `search' for #<Class:0x00007fd13e072288> Can you help me with this by updating answer
Hmmm. Can you fire up rails console and see if it recognizes ProductionProductivity7.search(search, compare) ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.