1

I solved this. See the answer I posted for details. Bascially I had a form in a form, with both having a POST action. I eliminated the outer form.

Update 3: This is almost working, but now my FavoritesController create method is giving a strange error:

wrong argument type Module (expected Class)

Here is the "Add to Favorites" button partial:

<%= form_for(current_user.favorites.build(followed_event_id: user_event.id)) do |f| %>
  <div class="hidden"><%= f.hidden_field :followed_event_id %></div>
  <%= f.submit "Add to favorites", class: "info_inline_control info_button_small user_event_summary_item" %>
<% end %>

Here is the favorites controller create action:

def create
  @user_event = UserEvent.find(params[:favorite][:followed_event_id])
  current_user.follow!(@user_event)
end

And here is the User model follow!() method

def follow!(user_event)
  favorites.create!(followed_event_id: user_event.id)
end

Update 2: When I view source, the form containing the "Add to Favorites" button is contained within the form for the search results item. So user searches for events, gets search results, and each item is rendered as a form with another form for the Add to Favorites button.

But that outer form has a method="post", and that seems to be the problem.

That outer form was created because I was using a form_for, so I removed that and now there is no outer form.But the favorite is saved when the "Add to Favorites" button partial is rendered, NOT when the button is clicked. That's what I need to solve now. So close...


Update: I am finally able to add a favorite, but unfortunately when the "Add to Favorites" button is clicked, in addition to saving the favorites record, the user event update action is being called. This is most significant when user unfollows the event, because that deletes that event, and its not their event.

Here is the favorites create method in FavoritesController:

def create
  @user_event = UserEvent.find(params[:favorite][:followed_event_id])
  current_user.follow!(@user_event)
end

Here is the follow() method in the User model:

def follow!(user_event)
  favorites.create!(followed_event_id: user_event.id)
end

Here is the partial with the "Add to Favorites" button:

<%= form_for(current_user.favorites.create!(followed_event_id: user_event.id)) do |f| %>
  <div class="hidden"><%= f.hidden_field :followed_event_id %></div>
  <%= f.submit "Add to favorites" %>
<% end %>

Could there be something wrong with the hidden field?

When a "favorite" relationship is created, in an abstract sense, the user event is being updated (because it is now associated with a user through the favorite), but I would not think it would trigger an update of the user event.


I hope the info I share here is enough to help you help me.

I have an event planning app, and users can create events. Users can also search for events and click a button to add events to their "favorites".

I've modeled this after Michael Hartl's great Rails Tutorial, in which he allows users to follow (and thus be followed by) other users.

My use of his paradigm differs because a user "follows" events, instead of following other users. In this sense, a user is "followed" by events, because if ten users follow a specific event, the event is kind of following those users. I hope I have that part of the abstraction correct.

My problem is that when the user clicks the "Follow" button, a row in the "favorites" table is not created (with following_user_id and followed_event_id). Instead, and somewhat mysteriously, the events_controller update action is called.

I should mention that the "Add to Favorites" button appears on the search results "show" page, which renders the _user_event.html.erb partial for each search result item.

So the user is on the search results "show" page, with an "Add to Favorites" button, and this button is part of an add favorites form, which when submitted, is submitting to update the event, which is wrong.

Here is some code, which I hope helps you understand my scenario. BTW, I really have two questions here, why is the add to favorites form submitting to update the event, and am I implementing this has_many through paradigm correctly. Thanks very much in advance.

-------------- user.rb MODEL --------------------
...
  has_many :user_events, dependent: :destroy
  has_many :favorites, foreign_key: "followed_event_id", dependent: :destroy
  has_many :followed_events, through: :favorites, source: :followed_event
...
  def following?(user_event)
    favorites.find_by_followed_event_id(user_event.id)
  end

  def follow(user_event)
    favorites.create!(followed_event_id: user_event.id)
  end

  def unfollow(user_event)
    favorites.find_by_followed_event_id(user_event.id).destroy    
  end

---------------- user_event.rb MODEL -------------------
...
  belongs_to :user
  has_many :favorites
  has_many :favorited_by, through: :favorites, source: :user
...

------------------------ favorite.rb MODEL --------------------
class Favorite < ActiveRecord::Base
  attr_accessible :followed_event_id

  belongs_to :following_user, class_name: "User"
  belongs_to :followed_event, class_name: "UserEvent"

  has_many :reverse_favorites, foreign_key: "followed_event_id",
                               class_name: "Favorite",
                               dependent: :destroy
  has_many :following_users, through: :reverse_favorites, 
                             source: :following_user                               

  validates :following_user_id, presence: true
  validates :followed_event_id, presence: true
end

----------------- config/routes.rb -----------------------
...
  resources                 :users do
    member do
      get :following_users, :followed_events 
    end
  end
...
  resources                 :user_events
  resources                 :favorites, only: [:create, :destroy]
...


---------------- favorites_controller.rb --------------
class FavoritesController < ApplicationController
  before_filter :signed_in_user

  def create
    @user_event = UserEvent.find(params[:favorite][:user_event])
    current_user.follow!(@user_event)
    redirect_to @user
  end

  def destroy
    @user_event = Favorite.find(params[:id]).followed_event
    current_user.unfollow!(@user_event)
    redirect_to @user
  end
end

----------------- migration --------------------
class CreateFavorites < ActiveRecord::Migration
  def change
    create_table :favorites do |t|
      t.integer :following_user_id
      t.integer :followed_event_id

      t.timestamps
    end
  end
end

----------------- search "show" view -----------------
<h2>Search Results</h2>    
<%= render @search.user_events %>

------------- _user_event.html.erb -------------
...
<% if (signed_in? && current_user && current_user.id != user_event.user_id) %>
  <%= render partial: "shared/add_remove_favorite", locals: { user_event: user_event } %>
<% end %>
<%= user_event.title %></span>
...

--------------- _add_remove_favorite.html.erb ------------
<% if current_user.following?(user_event) %>
  <%= render partial: 'shared/remove_favorite', locals: { user_event: user_event } %>
<% else %>
  <%= render partial: 'shared/add_favorite', locals: { user_event: user_event } %>
<% end %>

-------------- _add_favorite.html.erb ---------------------
<%= form_for(current_user.favorites.build(followed_event_id: user_event.id)) do |f| %>
  <div class="hidden"><%= f.hidden_field :followed_event_id %></div>
  <%= f.submit "Add to favorites" %>
<% end %>

--------------------- _remove_favorite.html.erb ---------------
<%= form_for(current_user.favorites.find_by_followed_event_id(user_event),
    html: { method: :delete }) do |f| %>
  <%= f.submit "Remove from favorites" %>
<% end %>

Lots of code, and I hope you understand my questions and can help. I'm about 70% done with my app, and have been loving Rails so far, but this problem is throwing me for a loop.

4

2 回答 2

1

解决了最后一个问题。我的FavoritesController 是从ActionController 继承的,这是一个错字,应该是ApplicationController。那不是核心问题。核心问题是我在一个表单中有一个表单,并且在生成的 HTML 中,两个表单都有一个 post 操作。因此,当单击“添加到收藏夹”按钮时,外部表单已提交。解决方案是将 div 从外部形式中取出。

这是我现在工作的保存到收藏夹实现的基本代码。只有我认为相关的代码。完整的代码太大。

感谢你的帮助!

------------ 迁移以创建收藏夹表 ------

class CreateFavorites < ActiveRecord::Migration
  def change
    create_table :favorites do |t|
      t.integer :following_user_id
      t.integer :followed_event_id

      t.timestamps
    end
  end
end

--------------- 添加路线 -----------

resources                 :users do
  member do
    get :following_users, :followed_events
  end
end

resources                 :favorites, only: [:create, :destroy]

---------------- 最喜欢的型号 -----------------

class Favorite < ActiveRecord::Base
  attr_accessible :followed_event_id

  belongs_to :following_user, class_name: "User"
  belongs_to :followed_event, class_name: "UserEvent"

  validates  :following_user_id, presence: true 
  validates  :followed_event_id, presence: true 
end

------------------ 用户模型 ----------------------

has_many :user_events, dependent: :destroy
has_many :favorites, foreign_key: :following_user_id, dependent: :destroy 
has_many :followed_events, through: :favorites, source: :followed_event

def following?(user_event)
  favorites.find_by_followed_event_id(user_event.id)
end

def follow!(user_event)
  favorites.create!(followed_event_id: user_event.id)
end

def unfollow!(user_event)
  favorites.find_by_followed_event_id(user_event.id).destroy
end

-------------------- 用户事件模型 ----------

belongs_to :user

has_many :favorites, foreign_key: :followed_event_id, dependent: :destroy 
has_many :following_users, through: :favorites, source: :following_user

-------------- 收藏夹控制器 -------------

class FavoritesController < ApplicationController
  before_filter :signed_in_user

  def create
    @user_event = UserEvent.find(params[:favorite][:followed_event_id])
    current_user.follow!(@user_event)
    redirect_to user_path(current_user)
  end

  def destroy
    @user_event = Favorite.find(params[:id]).followed_event
    current_user.unfollow!(@user_event)
    redirect_to user_path(current_user)
  end
end

---------------- 用户控制器 ----------------------------

def following_users
  @user_event = UserEvent.find(params[:id])
  @users = @user_event.following_users
end

 def followed_events
  @user = User.find(params[:id])
  @user_events = @user.followed_events
 end

------------ _add_remove_favorite.html.erb ----------------

<% if current_user.following?(user_event) %>
  <%= render partial: 'shared/remove_favorite', locals: { user_event: user_event } %>
<% else %>
  <%= render partial: 'shared/add_favorite', locals: { user_event: user_event } %>
<% end %>

------------- _add_favorite.html.erb ------------

<%= form_for(current_user.favorites.build(followed_event_id: user_event.id)) do |f| %>
  <div class="hidden"><%= f.hidden_field :followed_event_id %></div>
  <%= f.submit "Add to favorites", class: "info_inline_control info_button_small user_event_summary_item" %>
<% end %>

------------- _remove_favorite.html.erb ----------

<%= form_for(current_user.favorites.find_by_followed_event_id(user_event),
             html: { method: :delete }) do |f| %>
  <%= f.submit "Remove from favorites", class: "info_inline_control info_button_small user_event_summary_item" %>
<% end %>

-------------- 显示收藏夹的用户显示页面代码 show.html.erb ------------------

<h3 class="purple_text top_margin_thirty">Your Favorites</h3>
<div>
  <% if @user.followed_events.any? %>
    <h4 class="green_text info_inline_control">Your favorites include <%= pluralize(current_user.followed_events.count, "event") %> !</h4>
    <div class="favorites">
      <%= render @user.followed_events %>
    </div>
  <% else %>
    <h4 class="green_text no_events">You have no favorite events</h4>
    <%= link_to "Find an Event", new_search_path, class: "post_find_event_link" %>
  <% end %>
</div>
于 2013-06-30T19:10:51.160 回答
0

您在用户模型中有错误。它应该是:

class User < ActiveRecord::Base
  has_many :user_events, dependent: :destroy
  has_many :favorites, foreign_key: :following_user_id, dependent: :destroy
  has_many :followed_events, through: :favorites, source: :followed_event
  # ...
end

试试这个,看看会发生什么。我不确定这是否能解决您的错误。

于 2013-06-29T09:02:18.487 回答