R – attributes and constructors in rails

rubyruby-on-rails

I'm new to rails and don't even know if this is the correct way of solving my situation.

I have a "Club" ActiveRecords model which has a "has_many" association to a "Member" model. I want the logged in "Club" to only be able to administrate it's own "Member" so in the beginning of each action in the "Member" model I did something similar to the following:

def index
 @members = Club.find(session[:club_id]).members

to access the right members. This did not however turn out very DRY as I did the same in every action. So I thought of using something equivalent to what would be called a constructor in other languages. The initialize method as I've understood it. This was however not working, this told me why, and proposed an alternative. The after_initialize.

def after_initialize
 @club = Club.find(session[:club_id])
end

def index
 @members = @club.members
....

does not seem to work anyway. Any pointers to why?

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.members

Makes me think that the @club var isn't set at all.

Also, is this solution really a good one? This makes it hard to implement any kind of "super admin" who can manage the members in all of the clubs. Any ideas on where I am missing something?

Best Answer

You can use a before_filter. Define the filter in your ApplicationController (so that you can access it from any controller).

class ApplicationController < ActionController::Base

  # ..

  protected

    def load_members
      @members = if session[:club_id]
        Club.find(session[:club_id]).members
      else
        []
      end
    end

end

Then, load the filter before any action where you need it. For example

class ClubController < ApplicationController
  before_filter :load_members, :only => %w( index )

  def index
    # here @members is set
  end
end

Otherwise, use lazy loading. You can use the same load_members and call it whenever you need it.

class ClubController < ApplicationController
  def index
    # do something with members
    load_members.each { ... }
  end
end

Of course, you can customize load_member to raise an exception, redirect the client if @members.empty? or do whatever you want.