How can I subscribe a user when creating a new project?
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:
- You can't look up the project until it's actually been created so there is a database ID.
- 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. :grinning: :raised_hands: Your explanation helped a lot.
I still need to work on understanding the logic for associations.
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 %>
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. :)