Ian.mc
Ian.mc

Reputation: 1176

Extending model to include "helper" methods

I have a kind of social network website.

I have a logic to create the path for the user, and select an avatar for each user described in UsersHelper methods user_path(user) and user_avatar(user).

Instead I want to have methods like user.path and user.avatar, but I don't want to have that code inside the model file.

I tried extending the User class inside the helper:

module UsersHelper
  class User
    def avatar
      ...
    end
  end
end

That doesn't work - the method I added aren't recognized (I'm guessing Rails dynamically generates the ActiveRecord class on demand so my methods don't apply?)

I'd really appreciate ideas

Upvotes: 0

Views: 1526

Answers (3)

Ryan Brunner
Ryan Brunner

Reputation: 14851

Draper is an awesome little gem that does an excellent job of achieving the functionality you're looking for (adding view / presentation specific code while still making it "feel" like the model you're working with). We've removed almost all of our model-specific helpers after starting to use draper.

Basically, it works by defining decorators, which work like a wrapper around your model. A decorator looks and feels like the model it's decorating, but can have additional functionality defined on top of it. In addition, you can restrict access to certain fields and lock stuff down if you like.

For your example, adding a decorator would be as simple as:

(in app/decorators/user_decorator.rb)

class UserDecorator < ApplicationDecorator
  decorates :user

  def avatar
    # your implementation
  end

(in your controller)

def index
  respond_with UserDecorator.decorate(User.all)
end

(in your views)

<div class='avatar'><%= user.avatar %></div>
<div class='name'><%= user.name %></div>

Upvotes: 1

sarahhodne
sarahhodne

Reputation: 10106

First, there's a reason helpers are separated from models. According to the MVC pattern your model shouldn't know anything about your helpers, and not vice versa either (the latter is usually ignored in Rails, though).

But, if you want to do this, you need to do class ::User in model UsersHelper, or the following:

module UsersHelper
end

class User
end

The reason for this is that Ruby namespaces classes. So you defined UsersHelper::User, while your model is called User. Calling the class ::User or defining it outside the module forces it into the root namespace.

However, as I said, this is not the "correct" way to do it. A better way would be how you're already doing it, or maybe using a decorator pattern.

Upvotes: 1

Dominic Goulet
Dominic Goulet

Reputation: 8103

Helpers are intended to use with the views, not with the models.

If you wish to have something like user.avatar, you have to add it to your model.

If you want to stick it in the helpers, then in the UsersHelper add a user_avatar method.

Upvotes: 0

Related Questions