3

I am totally new to Ruby, and Rails. Currently, I am using helper methods. How can I write the same code as this in my Model 'User' so as to access all these variables from controller and view?

Writting code this way in helper is 100% functional:

module HomeHelper

  def init(user_id)
    @friends = Array.new    
    @followers = Array.new

    @user = User.find_by_id(user_id)    #Get User
    @friends = @user.users              #Get all his friends
                                        #
    @statuses = Array.new               #
    @friends.each do |friend|           #
      @statuses += friend.statuses      #Get all statuses for 'a' friend, then loop
    end                                 #
    @statuses += @user.statuses         #
    @statuses = @statuses.sort_by {|status| status.created_at}.reverse!

    @friendsof = Array.new
    @filtered_friendsof = Array.new

    @friends.each do |friend|
      @friendsof += friend.users
    end
    @friendsof.each do |friendof|
      unless (@friends.include?(friendof))
        if @user != friendof
          @filtered_friendsof << friendof
        end
      end
    end
  end

  @filtered_friendsof = @filtered_friendsof.uniq

end

Controller

class HomeController < ApplicationController
  def index
    @user_id=3
  end   
end

Model:

class User < ActiveRecord::Base
  has_many :statuses
  has_and_belongs_to_many(:users,
    :join_table => "user_connections",
    :foreign_key => "user1_id",
    :association_foreign_key => "user2_id")
  #has_many :user_connections
end
nitsas
  • 972
  • 7
  • 17
  • If i am getting you right.. you want your helper to be accessible across all controllers? – AnkitG Oct 13 '12 at 14:21
  • Is this piece of code supposed to go in 'Helper',as it is, or should go to 'Model'?And if it should go into Model, then how do I do it? –  Oct 13 '12 at 14:23

2 Answers2

4

Home controller:

class HomeController < ApplicationController
  def index
    @user = User.find(3)
  end 
end

User model:

class User < ActiveRecord::Base
  has_many :statuses
  has_and_belongs_to_many :friends,
    :class_name => 'User'
    :join_table => "user_connections",
    :foreign_key => "user1_id",
    :association_foreign_key => "user2_id"

  def combined_statuses
    (friends.map(&:statuses) + statuses).flatten.
      sort_by {|status| status.created_at}.reverse!
  end
end

Now, you don't need your helper method and in your view you can use:

@user.friends # instead of @friends
@user.combined_statuses # instead of @statuses

I'll let you figure out the rest, but I hope you get the general idea of pushing the logic into the model.

gylaz
  • 13,221
  • 8
  • 52
  • 58
  • Thanks!! But Am supposed to use Helpers in this way? I am a beginner. I dont know much about Models. I was pulling in data from database using 'Helpers',but later, I thought that the code I wrote in Helper was supposed to be in Model. ?? –  Oct 13 '12 at 14:42
  • Think of helpers as logic that is only necessary for the views. For example, if you want to display a link if a user is an admin, but not if a user is a regular member. Then you would define that logic in a helper, then in your view call 'edit_link(user)'. Thus, `edit_link` would only return a link if that user was an admin. I hope that makes sense. – gylaz Oct 13 '12 at 15:07
  • Then is it ok to write 'find_mutual_friends(to_find_mutual_friend_of_id)' code in Helper? Thanks, again! –  Oct 13 '12 at 15:38
  • No, finders should go into the model. You shouldn't really be using ActiveRecord directly in the view helpers. User model should have an instance method called `mutual_friends`. – gylaz Oct 13 '12 at 15:59
0

Most of that logic belongs in the User model. Nothing else needs to be actually doing those computations, and the User model has access to all the relevant pieces. There are additionally several other improvements that can be made. I'll try to add comments below to indicate these improvements.

Model

class User < ActiveRecord::Base
  has_many :statuses
  has_and_belongs_to_many :friends,            # now you can just say user.friends
    :class_name => 'User',                     # makes more sense semantically    
    :join_table => "user_connections",
    :foreign_key => "user1_id",
    :association_foreign_key => "user2_id"

  def friends_statuses
    (friends.map(&:statuses).flatten + statuses).sort_by!(&:created_at).reverse
    # Ruby has many great methods for Arrays you should use.
    # You can often avoid instantiating variables like the empty Arrays you have.
  end

  def second_order_friends
    (friends.map(&:friends).flatten.uniq - friends) - [self]
  end
end

Controller

class HomeController < ApplicationController
  def index
    user = User.find(7) # how do you decide which user you're displaying things for?
                        # this might be better off in 'show' rather than 'index'

    # here you can call all the methods you have for 'User', such as:
    # user.friends, user.statuses, user.friends_statuses, user.second_order_friends

    # to make things accessible in the view, you just need an @variable, e.g.:
    @friends = user.friends
    @latest_statuses = user.friends_statuses.first(10)
  end
Amit Kumar Gupta
  • 17,184
  • 7
  • 46
  • 64
  • Your post really is useful. Where can i learn methods like (friends.map(&:friends).flatten.uniq - friends) - [self] ?? –  Oct 13 '12 at 15:52
  • `map`, `flatten`, `uniq`, `sort_by!`, `reverse`, `-` are all methods of the `Array` class, you can read more [here](http://www.ruby-doc.org/core-1.9.3/Array.html) (or just Google "ruby array"). The `&:` is a handy shortcut; [this SO thread](http://stackoverflow.com/questions/1961030/ruby-ruby-on-rails-ampersand-colon-shortcut) is a good place to start reading about it. – Amit Kumar Gupta Oct 13 '12 at 16:02