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.