Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Ruby Building Social Features in Ruby on Rails Building the Friendship UI Creating the Friendship

Kelly Waters
Kelly Waters
3,005 Points

Strong Parameters in Rails 4 for user_friendships

I am having trouble getting the user_friendships working. I am using Rails 4, here's my code for the user_friendships_controller.rb:

class UserFriendshipsController < ApplicationController
  before_filter :authenticate_user!, only: [:new]

  def new
    if params[:friend_id]
      @friend = User.where(profile_name: params[:friend_id]).first
      @user_friendship = current_user.user_friendships.new(friend: @friend)
    else
      flash[:error] = "Friend required"
    end
  rescue ActiveRecord::RecordNotFound
    render file: 'public/404', status: :not_found  
  end

  def create
    if params[:user_friendship] && params[:user_friendship].has_key?(:friend_id)
      @friend = User.where(profile_name: params[:user_friendship][:friend_id]).first
      @user_friendship = current_user.user_friendships.new(friend: @friend)
      @user_friendship.save
      flash[:success] = "You are now friends with #{@friend.name_display}"
      redirect_to profile_path(@friend)
    else
      flash[:error] = "Friend not found"
      redirect_to root_url
    end
  end
end

and the model:

class UserFriendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'

end

The issue is that it does not appear to be sending the friend_id as a parameter. From terminal:

Started POST "/user_friendships" for 127.0.0.1 at 2014-03-29 12:21:19 -0700
Processing by UserFriendshipsController#create as HTML
  Parameters: {"utf8"=>"?", "authenticity_token"=>"RmRmN86rJl2ogB6E0re6naxWoCOEl8rw+7qO3ZJs2Yk=", "commit"=>"Yes, Add Friend"}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

The

 @user_friendship = current_user.user_friendships.new(friend: @friend)

line in the new and create methods of the controller is the part that confuses me. I have not used strong parameters with this case yet.

15 Answers

Brandon Barrette
Brandon Barrette
20,485 Points

So you have to use strong_parameters to allow the form data to pass through to the controller. That's why it doesn't show in the log. You should be adding friend_id to allow that to pass through.

Emily Martinez
Emily Martinez
13,096 Points

Does anyone have an example of how they got strong_parameters to work for them? So far I have changed my attr_accessible list from the UserFriendship model to look like this: UserFriendship.create(params.permit(:user, :friend, :user_id, :friend_id)) But I don't know where I'm supposed to put that (assuming it's even correct)? Do I add it to the create method of the UserFriendshipController? Or in the ApplicationController? Or somewhere else? Do I assign it to something? Everything I have attempted is not working. Please, help!

Kelly Waters
Kelly Waters
3,005 Points

Ahh yes, that was it. I did not end up using the strong_parameters gem, but I did have the hidden_field commented out in the form, because it was causing a crash earlier. Just had to switch to using .find instead of .where. Appears to be working well now. Thanks Brandon!

how did you do this exactly? I'm having the exact same problems...

Brandon Barrette
Brandon Barrette
20,485 Points

I recommend using strong_parameters that shipped with rails 4.0. From what I've read, the reason for the switch was for security issues using attr_accessible in earlier versions of rails.

Kelly Waters
Kelly Waters
3,005 Points

Oh I see. It is built into Rails. I have only used Rails 4, so I thought it was always there at first.

Kelly Waters
Kelly Waters
3,005 Points

Yes, for strong parameters, you have to declare what you what to pass in the controller now. So, yes, add it to the create method. Here is what I did:

def create
    if params[:user_friendship] && params[:user_friendship].has_key?(:friend_id)  
      # @friend = User.where(profile_name: params[:user_friendship][:friend_id]) 
      @friend = User.find(params[:user_friendship][:friend_id]) 
      @user_friendship = UserFriendship.request(current_user, @friend)

      respond_to do |format|
        if @user_friendship.new_record?
          format.html do 
            flash[:error] = "There was problem creating that friend request."
            redirect_to profile_path(@friend)
          end
          format.json { render json: @user_friendship.to_json, status: :precondition_failed }
        else
          format.html do
            flash[:success] = "Friend request sent."
            redirect_to profile_path(@friend)
          end
          format.json { render json: @user_friendship.to_json }
        end
      end        
    else
      flash[:error] = "Friend not found"
      redirect_to root_url
    end
  end

Notice I have the .where query commented out. This is because I just couldn't get it to find a @friend. I asked a friend of mine who is a rails expert and he said that using .find in this case is ok, because we only care about returning one object. However, if you wanted to make a list where people can check off boxes to add multiple people, you would have to use .where..

Let me know if that works!

Emily Martinez
Emily Martinez
13,096 Points

Hi Kelly,

Thanks for the response, but I think you may be a littler further along that I am with the Treebook project. I did try using @friend = User.find(params[:user_friendship][:friend_id]) , but it's still not working. I also don't see how you are passing in your strong parameters. ???

Kelly Waters
Kelly Waters
3,005 Points

Yeah, its a bit tough for me to understand as well. And yeah, I guess I am a few steps ahead. I will try and step back a bit. I'll see if I can explain it better. In the view (user_friendships/new.html.erb), here is what I have:

<%= form_for @user_friendship, method: :post do |form| %>
    <div class = "form form-action">
      <%= form.hidden_field(:friend_id, :value => @friend.id) %>
      <%= submit_tag "Yes, Add Friend", class: "btn btn-primary" %>
      <%= link_to "Cancel", profile_path(@friend), class: 'btn btn-default' %>
   </div>
<% end %>

This passes the friend_id as the object id of the new @friend object. I am not sure this is the best way to do this, but it worked for me.

Then in the user_friendships controller:

def create
    if params[:user_friendship] && params[:user_friendship].has_key?(:friend_id)
      @friend = User.find(params[:user_friendship][:friend_id])
      @user_friendship = current_user.user_friendships.new(friend: @friend)
      @user_friendship.save
      flash[:success] = "You are now friends with #{@friend.first_name}"
      redirect_to profile_path(@friend)
    else
      flash[:error] = "Friend not found"
      redirect_to root_url
    end
  end

This line:

@friend = User.find(params[:user_friendship][:friend_id])

is making the @friend instance variable, from the friend_id passed in from the form. The @user_friendship needs a user_id and a friend_id. So, the user_id is that of the current_user, and the friend_id is the one that gets passed from the form, in the hidden_field.

Emily Martinez
Emily Martinez
13,096 Points

Hi Kelly,

Thanks so much for the detailed follow up! I appreciate the thoroughness. It clarified some things.

Overall, I am following what you're saying, I understand that the @user_friendship needs a user_id and a friend_id, the later passed in from the hidden field. The problem I'm running into is that switching from using attr_accessible to strong_parameters is a little murky i.e. not just a matter of moving everything from the model to the controller and deciding to .permit all. Or so I'm discovering. . .

I ran into a similar problem with Devise early on, and had to implement a work around by adding a user parameter sanitizer to the lib, and calling it from the application_controller whenever the User class was instantiated. Granted, Devise has its own way of handling parameters that I won't pretend to understand.

But the point is, I am still learning ALL of this, so I'm never sure when these workarounds are gonna blow up and/or are interfering with cleaner solutions that I am using incorrectly b/c I'm still learning all of this and trashed up my project with the workarounds. I may just revert to the version of Rails used in the tutorial to get through this project without anymore headaches (as teachable as they may be).

But before I go, for fun, here is the current state of what happens when I try to create a user friendship (seems to still be passing a string-of-nonsense for value and returns "Friend not found"):

View source:

<form accept-charset="UTF-8" action="/user_friendships" 
class="new_user_friendship" id="new_user_friendship" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="&#x2713;" />
<input name="authenticity_token" type="hidden" value="wkLF5Zs7ALO2gaNrXC1bCBWIurbLkjd6gFWhvPnvPhI=" />
</div>

Terminal:

Started POST "/user_friendships" for 127.0.0.1 at 2014-04-03 13:30:15 -0700 Processing by UserFriendshipsController#create as HTML Parameters: {"utf8"=>"?", "authenticity_token"=>"wkLF5Zs7ALO2gaNrXC1bCBWIurbLkjd6gFWhvPnvPhI=", "commit"=>"Yes, Add Friend"} (0.1ms) begin transaction SQL (0.5ms) INSERT INTO "user_friendships" ("created_at", "state", "updated_at") VALUES (?, ?, ?) [["created_at", Thu, 03 Apr 2014 20:30:15 UTC +00:00], ["state", "pending"], ["updated_at", Thu, 03 Apr 2014 20:30:15 UTC +00:00]] (1.1ms) commit transaction Redirected to http://localhost:3000/ Completed 302 Found in 5ms (ActiveRecord: 1.6ms)

Brandon Barrette
Brandon Barrette
20,485 Points

You may want to look at the Rails 4 videos for ODOT (the ToDo app). Jason just released some videos about user authentication (without devise). Might be some helpful info there.

Emily Martinez
Emily Martinez
13,096 Points

Thanks, Brandon! I'll take a look at that soon.

I found this answer in another thread, and it worked for me. In the application_controller.rb :

   def profiles_params
      params.require(user).permit(:user_id, :friend_id, :users, :friend, :state, :first_name, :last_name, :user_friendship,       :full_name, :album, :albums_thumbnail, :title)
  end

Though, I doubt you still need this help :)

Emily Martinez
Emily Martinez
13,096 Points

OMG, are you kidding, thank you so much! I completely abandoned the Rails track because of the wall I hit with this. (Python is my new bff) Anyway, now I can finish. :)

I feel you! This is the first track where I've wondered if I might get completely stuck. So far, so good. Can I ask where you are learning Python? I saw yesterday that treehouse has hired a Python teacher.

Emily Martinez
Emily Martinez
13,096 Points

Hi Joy,

I actually just jumped into using the Beautiful Soup library: http://www.crummy.com/software/BeautifulSoup/bs4/doc/

Referencing Learn Python the Hard Way when I get stuck: http://learnpythonthehardway.org/book/

(I'm so addicted to web scraping now! :) )

Another site that's been really helpful for putting all this new knowledge to the test is Coderbyte.com. They have challenges, which you can complete in any language (JS, Python, Ruby). Highly recommend: http://www.coderbyte.com/

I just discovered Pluralsight.com recently. They have tons video tutorials, covering beginner, intermediate, and advanced topics in just about everything. I haven't tried any of their Python courses yet, but started one on Backbone.js, which is very thorough. If you like the video tutorial format of Treehouse or Lynda.com, and want to move on to more specific or advanced topics, this is a nice option: http://pluralsight.com/training/Courses/TableOfContents/python-fundamentals

There's also Codecadmy: http://www.codecademy.com/tracks/python

Can I ask what you're aspiring to do with all this new knowledge? I noticed you've been blazing through these courses, of which we seem to have chosen similar tracks. I'm curious as to what your mission is.

Wow! Thanks for all these references. This is amazing.

I come from an embedded programming background. I've been working in the networking industry for 15years. In a dream world, I'd love to make the switch to web development. I've fallen in love with coding again, and I desperately needed the creative aspect. I've been pushing IP packets around for too long :)

For now, I'm just trying to absorb as much as possible, and then decide what I love working with the most. It's a bit like being hit with a firehose at the moment. I am trying to take the time to play around and get better at each thing.

Python is next on my list. My son keeps telling me it's where I need to be, and I do see a lot of job listings with python. I feel like I have a ways to go before I would consider myself marketable. It's not easy to consider a switch at this point in my career.

How about you? Do you have a plan in mind?

Emily Martinez
Emily Martinez
13,096 Points

First, apologies to anyone reading who came here to read about Strong Parameters in Rails 4. The following will not help you.

Hi Joy,

My background is in visual and new media arts. My experience with programming has mostly been with MAX/MSP/Jitter and Processing. I've also hacked around with HTML/CSS/Javascript for a couple of years, but it's only recently that I've started to teach myself programming the right way e.g. learn specs, best practices, design patterns, reading tech tomes, filling in gaps, so many gaps, etc. Right now, I feel like my HTML/CSS skills are really solid, and my JS is getting better everyday. I, like you, also started to explore Rails and Python and PHP and whatever else, but at some point I started to feel like I was taking on too much and going in too many directions. After reevaluating, I've decided to focus on understanding to DOM and JavaScript. My goal right now is to start applying for junior front-end positions in 2-3 months. Eventually, when I gain more experience, I would like to move on to work on more meaningful research driven work. I'm really interested in what's happening with "big data", data visualization, augmented reality, artificial intelligence, etc. There is so much I want to explore. I also want to continue to make art and engage with critical practices, so I may also apply for an interactive media arts PhD. But we shall see where the road takes me. Right now I just need some financial stability and experience before I take the next really big leap. Web development seems like a great entry point, for me anyway.

As for switching careers, I think you can totally make the switch! I can imagine that doing something for so long (15 years) can weigh heavy on your sense of what's possible. But I think so much of what's possible, especially with web development, is a matter of prospective. There is a lot of demand for developers, the mobile market is blowing up; the web is growing and changing so much these days , even experienced developers are having to retrain and reinvent themselves. With that in mind, I'd say that you and I have just as much of a chance of breaking in to that world as any bored, uninspired developer already deep in it has of falling out of it. And sure, it may taken some time, and a lot of work, but it's completely possible. Not to mention, I think that with/because of all of these never-ending changes, there is a lot of room to build credibility by just paying attention to what's going on, what's new, what's interesting, and doing something with that knowledge/code; become active on github, contribute to open source projects, answer questions on stackoverflow, blog about all of this, etc.

If you're interested in front-end dev at all, here are some more resources that I've found quite useful:

A Baseline for Front-End Developers by Rebecca Murphey

Guidelines and standards for Front-end development at TMW

How browsers work

Or if you're considering any bootcamps (FREE and for women):

Ada Developers Academy

Outreach Program for Women (OPW)

Last, I think I'm going to take a break from Treehouse for a while, as I think I've already exhausted their resources for most of what I came here to learn.

Good luck with all! Email me if you want to stay in touch, for motivation, or whatever: mle626[at]gmail[dot]com