views:

38

answers:

1

I have two tables:

create_table "friendships", :force => true do |t|
    t.integer  "user1_id"
    t.integer  "user2_id"
    t.boolean  "hasaccepted"
    t.datetime "created_at"
    t.datetime "updated_at"
end

and

create_table "users", :force => true do |t|
    t.string   "email"
    t.string   "password"
    t.string   "phone"
    t.boolean  "gender"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "firstname"
    t.string   "lastname"
    t.date     "birthday"
end

I need to show the user a list of Friendrequests, so I use this method in my controller:

def getfriendrequests
    respond_to do |format|
        case params[:id]
            when "to_me"
                @friendrequests = Friendship.find(:all, :conditions => { :user2_id => session[:user], :hasaccepted => false })
            when "from_me"
                @friendrequests = Friendship.find(:all, :conditions => { :user1_id => session[:user], :hasaccepted => false })
        end
        format.xml  { render :xml  => @friendrequests }
        format.json { render :json => @friendrequests }
    end
end

I do nearly everything using AJAX, so to fetch the First and Last name of the user with UID user2_id (the to_me param comes later, don't worry right now), I need a for loop which make multiple AJAX calls. This sucks and costs much bandwidth. So I'd rather like that getfriendrequests also returns the First and Last name of the corresponding users, so, e.g. the JSON response would not be:

[
  {
    "friendship": {
      "created_at": "2010-02-19T13:51:31Z",
      "user1_id": 2,
      "updated_at": "2010-02-19T13:51:31Z",
      "hasaccepted": false,
      "id": 11,
      "user2_id": 3
    }
  },
  {
    "friendship": {
      "created_at": "2010-02-19T16:31:23Z",
      "user1_id": 2,
      "updated_at": "2010-02-19T16:31:23Z",
      "hasaccepted": false,
      "id": 12,
      "user2_id": 4
    }
  }
]  

but rather:

[
  {
    "friendship": {
      "created_at": "2010-02-19T13:51:31Z",
      "user1_id": 2,
      "updated_at": "2010-02-19T13:51:31Z",
      "hasaccepted": false,
      "id": 11,
      "user2_id": 3,
      "firstname": "Jon",
      "lastname": "Skeet"
    }
  },
  {
    "friendship": {
      "created_at": "2010-02-19T16:31:23Z",
      "user1_id": 2,
      "updated_at": "2010-02-19T16:31:23Z",
      "hasaccepted": false,
      "id": 12,
      "user2_id": 4,
      "firstname": "Mark",
      "lastname": "Gravell"
    }
  }
]   

I thought of a for loop in the getfriendrequests method, but I don't know how to implement this, and maybe there is an easier way. It must also work for XML. Can anyone help me? Thanks

A: 

When you call

render :xml  => @friendrequests

Rails iterates each element in the array and calls the ActiveRecord::Base#to_xml method. Likewise, the :json option means a call to ActiveRecord::Base#to_json.

Both to_xml and to_json have a :methods option which contains an array of methods to include in the serialization.

The solution is really straightforward. Override these methods.

class Friendship

  # ...

  def firstname
    # here get the first name
  end

  def lastname
    # here get the last name
  end

  def to_xml(options = {})
    options[:methods] ||= [:firstname, :lastname]
    super(options)
  end

  def to_json(options = {})
    options[:methods] ||= [:firstname, :lastname]
    super(options)
  end

end
Simone Carletti
Cool, but how do I make sure Rails only does this for getfriendrequests and not for other methods?
Time Machine
You could write something like `to_json_with_names` that could wrap what Simone has described above.
theIV
You should also add `:include => :userX` to the join table to cut down on DB queries. Where :userX is the association on FriendshipRequest that corresponds to the other user in the table (not current user)
EmFi