首页 > 解决方案 > 从视图调用控制器方法的问题

问题描述

我有一个具有以下方法的书籍控制器:

book_controller.rb

  def set_as_reading
    if (user_signed_in?)
     if (current_user.user_type == "0")
        @book = Book.find(params[:id])
        @reading = Reading.new
        @reading.book_id = @book.id
        @reading.profile_id = session[:current_profile]["id"]
        @reading.is_finished = false
        @reading.save 
      else
        redirect_to books_path
      end
    else
      redirect_to root_path
    end
  end

  def remove_from_reading
    if (user_signed_in?)
      if (current_user.user_type == "0")
        @book = Book.find(params[:id])
        @reading = Reading.where(profile_id: session[:current_profile]["id"]).where(book_id: @book.id)
        @reading.is_finished = true
        @reading.save
      else
        redirect_to books_path
      end
    else
      redirect_to root_path
    end
  end

我已经定义了以下路线:

路线.rb

  post 'books/:id', to: 'books#set_as_reading', as: :set_as_reading
  post 'books/:id', to: 'books#remove_from_reading', as: :remove_from_reading

我在显示视图中使用这些方法如下:

显示.html.erb

  <% if current_user.user_type == "0" %> 
    <%= link_to "Add to Reading list", @book, method: :set_as_reading, class: 'btn btn-danger',
    style: 'margin-right:10px' %>
    <%= link_to "Finished", @book, method: :remove_from_reading, class: 'btn btn-danger',
    style: 'margin-right:10px' %>
  <% end %> 

每当我单击“添加到阅读列表”时,它都会正常工作,它会调用该set_as_reading方法。但是如果我想设置为“完成”,而不是调用remove_from_reading,它调用set_as_reading. 我怎样才能解决这个问题?先感谢您。

编辑

耙路线输出:

                   books GET    /books(.:format)                       books#index
                         POST   /books(.:format)                       books#create
                new_book GET    /books/new(.:format)                   books#new
               edit_book GET    /books/:id/edit(.:format)              books#edit
                    book GET    /books/:id(.:format)                   books#show
                         PATCH  /books/:id(.:format)                   books#update
                         PUT    /books/:id(.:format)                   books#update
                         DELETE /books/:id(.:format)                   books#destroy
          set_as_reading POST   /books/:id(.:format)                   books#set_as_reading
     remove_from_reading POST   /books/:id(.:format)                   books#remove_from_reading

标签: ruby-on-railsrubyroutescustom-routes

解决方案


问题是您有一条路线指向两个不同的地方。Rails 只是抓取它看到的第一个。

每条路线都必须是唯一的:

post 'books/:id/reading', to: 'books#set_as_reading', as: :set_as_reading
post 'books/:id/finished', to: 'books#remove_from_reading', as: :remove_from_reading

此外,您的嵌套 if 语句并不总是导致重定向。

如果我已登录并且我的 user_type 为“0”,我应该在@reading.save完成后发送到哪里?

而且你的代码很胖。它可以更清洁。

我建议这样的事情:

class BooksController < ApplicationController
  before_action :set_book, only: %w[set_as_reading remove_from_reading]
  before_action :check_user, only: %w[set_as_reading remove_from_reading]

  def set_as_reading
    @reading = Reading.create(
      book: @book,
      profile_id: session[:current_profile]["id"], # is this the same as current_user?? If so, just use current_user.id
      is_finished: false
    )

    redirect_to somewhere_path # this is missing currently
  end

  def remove_from_reading
                                         # is this the same as current_user?? If so, just use current_user.id
    @reading = Reading.where(profile_id: session[:current_profile]["id"]).where(book_id: @book.id)

    # what happens if no record is found??
    redirect_to somewhere_path and return unless @reading.present?

    @reading.update(is_finished: true)

    redirect_to somewhere_path and return # this is missing currently
  end

  private

  def set_book
    @book = Book.find(params[:id])
  end

  def check_user
    redirect_to root_path unless user_signed_in? and return

    redirect_to books_path unless current_user.user_type == '0' and return
  end
end

推荐阅读