I just finished Ruby on Rails 3 Tutorial. The final chapter is quite complex. The tutorial throughout the book basically creates a site where Users can post Microposts. Also, each User can Follow any other User and then the following User’s Microposts will show up on the original User’s Micropost feed.
My question has to do with why the create action inside the RelationshipsController has the params variable contain a two-dimensional array.
Here’s the code.
User
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id",
class_name: "Relationship", dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
end
Micropost
class Micropost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
end
Relationship
class Relationship < ActiveRecord::Base
attr_accessible :followed_id
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
end
I think this is the code that creates the two-dimensional params variable (but why?)
<%= form_for(current_user.relationships.build(followed_id: @user.id), remote: true) do
|f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
RelationshipsController
class RelationshipsController < ApplicationController
def create
@user = User.find(params[:relationship][:followed_id])
current_user.follow!(@user)
respond_to do |format|
format.html { redirect_to @user }
format.js
end
end
end
So maybe I just answered my own question, but I’ve never seen a two-dimensional array for a params variable. Can someone maybe shed some light on this?
oh, maybe I should post my routes.rb file as well:
SampleApp::Application.routes.draw do
resources :users do
member do
get :following, :followers
end
end
resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
root to: 'static_pages#home'
end
thanks,
mike
Short Answer:
This is not a 2-dimensional array, it is a nested associative array. The reason you use it is to get at the field that you actually want.
Long Aswer:
Assumption from tutorial: When a user clicks the follow button, the goal is to call
current_user.follow!(other_user). I’ll walk you through how the code is achieving this. All of the magic is in the Relationship Controller and the form_for function in the view.First, you make a form for a new relationship. Because it is a nested resource, you build it through the association.
But a brand new Relationship object that only corresponds to one user doesn’t mean much. Instead, pass in an associative array of values to initialize the object to. In this case, the other user’s id. So you assign the :followed_id attribute of the Relationship object you are building to @user.id, or the user you are trying to follow.
When you form_for on an object, you can access the attributes of the object. In this case if we look at the Relationship model, only :followed_id is accessible.
Finally, we need to capture the followed_id in the form submission because the goal of the form is to be able to call
current_user.follow!(other_user)when the follow button is clicked. So we pass in the followed_id as a hidden field so it is accessible inparamsin the controller, but also the user does not see it in the view itself.Finally, when the button is clicked, because the form is for a new Relationship object, the create action is called for the Relationship controller. In there, to access the relationship object corresponding to the form you do it the same way as other forms in the tutorial –
But you don’t want the relationship object, you want the user object of the one to follow so you can call
follow!. This is easy. Just find the user in the database from the id. How to get the followed_id? It is an attribute of the Relationship object from the form.I think its worth noting that when you make a new user object, you use params[:user]. This is just an associative array and you could access fields of it if you wanted to like
Hopefully that made sense. It is just an nested associative array Rails uses to keep track of parameters such as those from submitting a form.