Rails:使用has_many关系时link_to(...,remote:true)的行为不一致

时间:2016-01-22 16:10:38

标签: javascript ruby-on-rails ajax has-many helpers

在Rails应用程序中使用常规路由与AJAX时,我遇到了不一致的行为。我有一个链接,其功能是销毁has_many :through关系。当不使用AJAX时,没有问题。当使用AJAX(即remote:true)时,链接会破坏关系以及所有者对象。

以下是详细信息:

我有一个模型ReaderBookFavorite的简单应用程序。读者has_many通过收藏夹预订,并通过收藏夹预订has_many本书。当我使用链接到"从收藏夹中移除"时,在使用AJAX时也会销毁该书。如果我没有远程:true,则不会发生此问题。这是服务器日志:

Started DELETE "/favorites/5" for ::1 at 2016-01-22 08:06:03 -0800
Processing by FavoritesController#destroy as JS
  Parameters: {"id"=>"5"}
  Favorite Load (0.2ms)  SELECT  "favorites".* FROM "favorites" WHERE     "favorites"."id" = ? LIMIT 1  [["id", 5]]
  Book Load (0.1ms)  SELECT  "books".* FROM "books" WHERE "books"."id"     = ? LIMIT 1  [["id", 5]]
   (0.1ms)  begin transaction
  SQL (0.3ms)  DELETE FROM "favorites" WHERE "favorites"."id" = ?      [["id", 5]]
   (1.9ms)  commit transaction
Redirected to http://localhost:3000/books/5
Completed 302 Found in 5ms (ActiveRecord: 2.5ms)


Started DELETE "/books/5" for ::1 at 2016-01-22 08:06:03 -0800
Processing by BooksController#destroy as JS
  Parameters: {"id"=>"5"}
  Book Load (0.1ms)  SELECT  "books".* FROM "books" WHERE "books"."id"     = ? LIMIT 1  [["id", 5]]
   (0.1ms)  begin transaction
  Favorite Load (0.2ms)  SELECT "favorites".* FROM "favorites" WHERE     "favorites"."book_id" = ?  [["book_id", 5]]
  SQL (0.2ms)  DELETE FROM "books" WHERE "books"."id" = ?  [["id", 5]]
   (0.9ms)  commit transaction
Redirected to http://localhost:3000/books
Completed 302 Found in 7ms (ActiveRecord: 1.5ms)

以下是我认为的相关代码:

book.rb

class Book < ActiveRecord::Base
  has_many :favorites, class_name: "Favorite",
                    foreign_key: "book_id",
                    dependent: :destroy
  has_many :readers, through: :favorites
end

reader.rb

class Reader < ActiveRecord::Base
  has_many :favorites, class_name: "Favorite",
                    foreign_key: "reader_id",
                    dependent: :destroy
  has_many :books, through: :favorites
  def add_favorite(book)
    return if Favorite.exists?(book_id:book.id,reader_id:self.id)
    favorites.create(book_id: book.id, reader_id: self.id)
    self.reload
  end
end

favorite.rb

class Favorite < ActiveRecord::Base
end

我有一个&#39; link_to&#39;在书籍/节目视图中说&#34;添加到收藏夹&#34;如果没有读者与读者之间的关系并且&#34;从收藏夹中移除&#34;如果有书籍读者关系。在辅助模块中生成正确的链接。

books_helper.rb

module BooksHelper
  def favorites_link_for(reader, book)
    if reader && Favorite.exists?(book_id: book.id, reader_id:    reader.id)
      link_to("Remove From Favorites", Favorite.find_by(book_id: book.id, reader_id: reader.id), :method => 'delete', remote: true)

    elsif reader && !Favorite.exists?(book_id: book.id, reader_id: reader.id)
      link_to("Add To Favorites", favorites_path(book_id: book.id, reader_id: reader.id), :method => 'post', remote: true)
    end
  end
end

唯一感兴趣的控制器是favorites_controller.rb:

class FavoritesController < ApplicationController
  def create
    reader = Reader.find(params[:reader_id])
    @book = Book.find(params[:book_id])
    reader.add_favorite(Book.find(params[:book_id]))
    redirect_to @book
  end

  def destroy
    debugger
    fav = Favorite.find(params[:id])
    @book = Book.find(fav.book_id)
    fav.destroy
    redirect_to @book
  end
end

唯一感兴趣的是书籍/节目:

<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @book.name %>
  <%= favorites_link_for(Reader.last, @book) %>
</p>

<%= link_to 'Edit', edit_book_path(@book) %> |
<%= link_to 'Back', books_path %>

完整代码可在此处获得:https://github.com/JenDobson/rails-with-remote-issue/tree/broken Rails版本为4.2.2。

1 个答案:

答案 0 :(得分:0)

问题是由于在FavoritesController#destroy中使用了行redirect_to @book引起的。当我删除该行时一切正常。无论如何都需要修改该行以允许在html和js下进行不同的页面响应,尽管我仍然不理解为什么redirect_to @book导致书籍记录在JS下被删除而不是在HTML下被删除。我很高兴接受任何可以进一步启发我的人的回答。

固定控制器如下所示:

class FavoritesController < ApplicationController
def create
    @reader = Reader.find(params[:reader_id])
    @book = Book.find(params[:book_id])
    @reader.add_favorite(Book.find(params[:book_id]))
    respond_to do |format|
      format.html { redirect_to @book }
      format.js
    end
end

def destroy
    fav = Favorite.find(params[:id])
    @book = Book.find(fav.book_id)
    @reader = Reader.find(fav.reader_id)
    fav.destroy
    respond_to do |format|
      format.html { redirect_to @book }
      format.js
    end
  end
end

github上的代码已修复:https://github.com/JenDobson/rails-with-remote-issue/tree/master