简体   繁体   中英

Rails 3.2: How do I access the current model instance inside of a helper module?

In my rails model Post.rb I have the following methods setup:

  def category_names(seperator = ", ")
    categories.map(&:name).flatten.join(seperator).titleize
  end

  def publish_date
    read_attribute(:publish_date).strftime('%A, %b %d')
  end

I would like to move these into PostsHelper module under helpers. But get a no-method error when I do so because I guess the reference to self is lost.

So how can I fix this? Is a helper module the wrong place for these methods?

Helper methods are designed mainly to be used in views, if I'm not mistaking.

What I'm sure about is your helper methods are outside of the scope of your model, meaning you need to pass to them the attribute to work with. Example:

  def category_names(categories, seperator = ", ")
    categories.map(&:name).flatten.join(seperator).titleize
  end

And call in your view:

category_names @post.categories

If you find your self writing "helper" method that are not exclusively used in your view, you could create a service object and include them in your model.

Edit: Service object

You can create a "services" directory under "app" directory and create your classes there.

Let me give you an example. I got a User model class, and I want to group all password related methods in a UserPassword service object.

User class:

class User < ActiveRecord::Base
  include ::UserPassword
  ...
end

UserPassword service object:

require 'bcrypt'

module UserPassword
  def encrypt_password
    if password.present?
      self.password_salt = BCrypt::Engine.generate_salt
      self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
    end
  end

  module ClassMethods
    def authenticate(email, password)
      user = find_by_email email
      if user and user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
        user
      end
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

So my User instanced object (ie u = User.first ) can call u.encrypt_password , and my User class can call User.authenticate .

There is maybe other way, but I find it flexible and easy to write and maintain :)

Helpers are always intended to help views, But if you want your Models to be clean and keep the unrelated methods as separate try using concerns in Rails 3. Concerns directory will be present by default in Rails 4.

There is a nice blogpost by DHH for same.

http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM