Reputation: 343
I have three models User
, Anime
and Animelist
.
A user
is able to add an anime
to their animelist
. This works just fine but i don't want a user
to be able to add the same anime
countless times to their list.
How can i set it up so after a user adds a anime to their list an edit pop-up form/button pops out with the info they put in.
I have a pop-up window in the animes/show page to reveal a form that a user has to fill to add a anime to their list. Hopefully I'm making my self clear.
Animelist _form
<%= simple_form_for [@anime, @animelist] do |f| %>
<%= f.input :status %>
<%= f.input :rating %>
<%= f.input :rewatched %>
<% end %>
animes/show page pop-up code
<p><a data-open="exampleModal1">Add to Animelist</a></p>
<div class="reveal form" id="exampleModal1" data-reveal>
<%= render partial: 'animelists/form' %>
<button class="close-button" data-close aria-label="Close modal" type="button">
<span aria-hidden="true">×</span>
</button>
</div>
Animelist controller
def new
@anime = Anime.friendly.find(params[:anime_id])
@animelist = Animelist.new
end
def create
@anime = Anime.friendly.find(params[:anime_id])
@animelist = Animelist.new(animelist_params)
@animelist.user_id = current_user.id
@animelist.anime_id = @anime.id
if @animelist.save
redirect_to :back
else
render :new
end
end
Anime controller
def show
@anime = Anime.friendly.find(params[:id])
@animelist = Animelist.new
end
Upvotes: 1
Views: 663
Reputation: 76774
The way you'd do this is to use a validation on the AnimeList
model to make sure each anime_id
is unique when scoped with user_id
:
#app/models/anime_list.rb
class AnimeList < ActiveRecord::Base
belongs_to :user
belongs_to :anime
validates :anime, uniqueness: { scope: :user_id, message: "%{attribute} already added" }
end
This will make each new AnimeList
fail if it you're using the same @anime.id
& @user.id
, an error which you can output on your form.
Structure
There are some issues with your overall structure, which should be addressed if you want to show the errors properly:
#config/initializers/friendly_id.rb
...
config.use :finders #-> uncomment so you don't need to call Model.friendly.find any more
#config/routes.rb
resources :animes do
resources :anime_lists, only: [:create, :destroy], path_names: { create: "add", destroy: "remove" } #-> url.com/animes/:anime_id/add
end
#app/controllers/animes_controller.rb
class AnimesController < ApplicationController
def show
@anime_list = current_user.anime_lists.new
end
end
#app/controllers/anime_lists_controller.rb
class AnimeListsController < ApplicationController
def create
@anime = Anime.find params[:anime_id]
@animelist = current_user.anime_lists.new animelist_params
respond_to do |format|
format.js
end
end
def destroy
@anime = Anime.find params[:anime_id]
@animelist = current_user.anime_lists.find(params[:id]).destroy
end
private
def animelist_params
params.require(:anime_list).permit(:status, :rating, :rewatched).merge(anime_id: @anime.id)
end
end
This will clean up your controller, to which you'll be able to use:
#app/views/anime_lists/create.js.erb
$("#anime_list").html("<%=j render partial: \"anime_list/form\", locals: { anime_list: @anime_list } %>");
#app/views/anime_lists/_form.html.erb
<%= simple_form_for anime_list, url: anime_anime_list_path(@anime), remote: true do |f| %>
<%= f.input :status %>
<%= f.input :rating %>
<%= f.input :rewatched %>
<%= f.submit %>
<% end %>
Update
Your error mentions there is no animelist
method for User
:
This means every time your request hits the controller, it's trying to fire @user.animelist
; since the animelist
method does not exist, it's spitting out the error.
Always remember that JS/Ajax requests are just pseudo
requests. Every time you use HTTP
, you have to send a request to the server. That request is then processed. You're never in the dark about errors -- they'll always be in the server logs somewhere.
I would surmise the issue is to do with the CamelCase
(or lack thereof) of your anime_list
association:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :animelists #-> model name "animelist.rb"
has_many :animes, through: :anime_lists
end
#app/user/animelist.rb
class Animelist < ActiveRecord::Base
belongs_to :user
belongs_to :anime
end
On that front, I also made a small error calling current_user.animelist
-- it should be current_user.anime_lists
(plural). This will likely fix your issue.
Upvotes: 1