Wesly
Wesly

Reputation: 343

How to submit a form in a different page and then make an edit form display after being submitted

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">&times;</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

Answers (1)

Richard Peck
Richard Peck

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:

enter image description here

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

Related Questions