Skip to main content

How can I subscribe a user when creating a new project?

Ruby • Asked by 6696

How can I subscribe a user when creating a new project?

I'm having a hard time on the create method. Currently this is my code:

Projects controller

  def create
    @project = Project.new(project_params)

    @project = Project.find(params[:project_id])
    current_user.subscriptions.create(project: project)

    respond_to do |format|
      if @project.save
        format.html { redirect_to @project, notice: 'Project was successfully created.' }
        format.json { render :show, status: :created, location: @project }
      else
        format.html { render :new }
        format.json { render json: @project.errors, status: :unprocessable_entity }
      end
    end
  end

Project Model

class Project < ApplicationRecord

  has_many :subscriptions
    has_many :users, through: :subscriptions

end

User Model

class User < ApplicationRecord

  has_many :subscriptions
  has_many :projects, through: :subscriptions

end

Couple things I notice off the bat:

  1. You can't look up the project until it's actually been created so there is a database ID.
  2. You can't create the subscription just yet either since the project hasn't been saved yet.

Here's what I would do:

 def create
    @project = Project.new(project_params)
        @project.subscriptions.new(user: current_user)

    respond_to do |format|
      if @project.save
        format.html { redirect_to @project, notice: 'Project was successfully created.' }
        format.json { render :show, status: :created, location: @project }
      else
        format.html { render :new }
        format.json { render json: @project.errors, status: :unprocessable_entity }
      end
    end
  end

This is going to build the project in memory first. Then it creates an associated Subscription record in memory as well, but inside the project. Since the two are associated in memory, this will make sure that when you save the @project the subscription also gets saved and both will get inserted into the database as long as the validations pass.


Thanks Chris! It worked. Your explanation helped a lot.

I still need to work on understanding the logic for associations.


Chris! How can I hide a project when a user is not subscribed to a project?


If you are using Devise you can call usersignedin? to determine if a user is or not logged in.

<% if user_signed_in? %>
    Code to display when the user is signed in
<% else %>
    Code to display when the user is not signed in
<% end %>

To "hide" projects, you can set something like this in your controller (most likely in your set_model method):

def set_params
  current_user.subscriptions.find(params[:id])
end

Thanks Jack and Steve! After a couple of days, this code seeme to do the thick. But it seems abit smelly. What do you guys think? Can this be improved?

  def show
     begin
       @project = current_user.projects
         .joins(:subscriptions)
         .where(subscriptions: {user_id: current_user.id})
         .find(params[:id])
     rescue ActiveRecord::RecordNotFound => e
       redirect_to root_path, notice: 'No estas subscrito'
     end
   end

I think you should be able to simply do the following instead:

@projects = current_user.projects.find(params[:id])

The trick here is that Rails knows how to do the join and where automatically because the relationship is defined as "has_many through". The has_many means it knows it must join, and through means that it needs to join twice.

Your query should work, but you're basically redefining exactly what Rails is doing internally so you can get rid of the join and where and it should produce the same output. :)


Wow! Thanks for taking the time to answer. Always so helpful Chris!


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 27,623+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.