Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby Building Social Features in Ruby on Rails Adding State Mutual Friendship

Dave Faliskie
Dave Faliskie
17,793 Points

Making a "friendship" between a user and another table

Similar to making a friendship I am trying to have a user be linked to an application. so Instead of having two users in a join table I have one user and one app, where the app is a completely different table from the user.

The part I cant figure out is creating two entries into the join table through the request method.

what I have

def self.request(user, app)
        transaction do
            app_apply1 = create(user: user, app: app, state: 'pending')

            app_apply2 = create(user: app, app: user, state: 'requested')

            app_apply1.send_request_email 
            app_apply1
        end
    end

This doesn't work because for app_apply2 I'm trying to set an application as a user and a user to and application. In the videos they were both users so it wasn't a problem. heres my controller.

    def create 
        if params[:user_app] && params[:user_app].has_key?(:app_id)
            @app = JobListing.find(params[:user_app][:app_id])
            @user_app = UserApp.request(current_user, @app)
            if @user_app.new_record?
                flash[:error] = "Sorry, your application can not be processed at this time."
            else
                flash[:notice] = "Your Application has been sent to " + @app.company_name 
            end
            redirect_to user_path(current_user)
        else
            flash[:error] = "Company Required"
            redirect_to users_path
        end
    end

app is used in the join table to represent a JobListing, so app is actually a JobListing.

So how do I add the second entry into my join table? Or is there a better way to achieve the same thing using a different method?

Any help would be great! Thanks

1 Answer

Brandon Barrette
Brandon Barrette
20,485 Points

So you should instead use a has_many: through association. Create a new model called app_users which has the columns user_id, app_id, and state (make this an integer).

Note that enum requires at least Rails 4.1

Then, in your app_users model:

class AppUser < ActiveRecord::Base

   belongs_to :user
   belongs_to :app

   enum state: { pending: 0, requested: 1, accepted: 2 }

Your user model would look like:

class User < ActiveRecord::Base

   has_many :app_users
   has_many :apps, through: app_users

Your app model would look like:

class App < ActiveRecord::Base

   has_many :app_users
   has_many :users, through: app_users

This will allow you to call

User.apps (to show all apps for the user) App.users (to show all users for an app)

Then using the state on the app_users model, you could actually write associations for the particular states. For example:

class User
has_many :pending_apps, -> { where app_users: { state: 0 }}, through: :user_apps, source: :app

Hope that helps! Ask away if you need more clarification. Happy coding =)

Dave Faliskie
Dave Faliskie
17,793 Points

Thanks for the detailed response! I did have to add another column for the other user (who posted the app) so both could see view the actions on the app. Would you recommend using the

 enum state: { pending: 0, requested: 1, accepted: 2 }

Is it better for the database to use numbers instead of strings? What are the pro/cons of using numbers instead of strings?

Brandon Barrette
Brandon Barrette
20,485 Points

You definitely want to use the enum integer column if you have Rails > 4.1

Reason is because with strings, you would have to say

if app_user.state == "pending" # (return true or false)
   do this
end

But with enum, you can easily say:

if app_user.pending? # (return true or false)
   do this
end

There are lots of nifty calls you can make with the enum. I'd check out the documentation here:

http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html

And then a good article here:

http://dev.mikamai.com/post/82355998967/rails-4-1-activerecord-enums

I actually used enums for the friendship model and also put an enum on my user model for user roles. With enum, you can replace the state machine with some quick callbacks.