Rails Favorites Model Association, link_to not producing html - ruby-on-rails

I am trying to implement a favorite relationship in my Ruby on Rails app. The route, controller, and relationship all appear to be working but link_to "favorite" is not working, by which I mean it is not even producing the html link, though it is throwing no error. I am following the example here Implement "Add to favorites" in Rails 3 & 4.
Here is the code:
routes.rb
resources :locations do
put :favorite, on: :member
end
locations_controller.rb
class LocationsController < ApplicationController
....
def favorite
type = params[:type]
if type == "favorite"
current_user.favorites << #location
redirect_to :back, notice: 'You favorited #{#location.name}'
elsif type == "unfavorite"
current_user.favorites.delete(#location)
redirect_to :back, notice: 'Unfavorited #{#location.name}'
else
# Type missing, nothing happens
redirect_to :back, notice: 'Nothing happened.'
end
end
end
user.rb
class User < ActiveRecord::Base
....
# Favorite locations of user
has_many :favorite_locations # just the 'relationships'
has_many :favorites, through: :favorite_locations # the actual recipes a user favorites
....
end
location.rb
class Location < ActiveRecord::Base
....
# Favorited by users
has_many :favorite_locations # just the 'relationships'
has_many :favorited_by, through: :favorite_locations, source: :user
end
view/locations/show.html.erb
<% provide(:title, #location.name) %>
....
<% link_to "favorite", favorite_location_path(#location, type: "favorite"), method: :put %>
<% link_to "unfavorite", favorite_location_path(#location, type: "unfavorite"), method: :put %>

Looks like you forgot the = in the <% %>, should be:
<%= link_to "favorite", favorite_location_path(#location, type: "favorite"), method: :put %>

Related

I need to add a destroy function for decline option in my follow request page

I am new to rails and I am creating a app in which a clone like twitter. The users are connected with each other by sending request first and the corresponding user accepts or deletes the request. I followed michael-hartl book.
User model:
attr_accessible :email, :name, :password, :password_confirmation, :id
has_many :reverse_requests, foreign_key: "requested_id", class_name: "Request", dependent: :destroy
has_many :requesters, through: :reverse_requests, source: :requester
has_many :requests, foreign_key: "requester_id", dependent: :destroy
has_many :requested_users, through: :requests, source: :requested
Accept or decline view:
<ul class="users">
<% #users.each do |user| %>
<%= link_to gravatar_for(user, size: 30), user %>
<%= link_to user.name, user %>
//Accept which invokes create
<%= form_for(current_user.relationships.build(follower_id: user.id)) do |f| %>
<%= f.hidden_field :follower_id %>
<%= f.submit "Accept", class: "btn btn-large btn-primary" %>
<% end %>
//Decline which invokes destroy
<%= form_for(user.requests.find_by_requested_id(current_user),
html: { method: :delete }) do |f| %>
<%= f.submit "Decline", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
</ul>
Requests controller:
def create
#user = User.find(params[:request][:requested_id])
current_user.request!(#user, 2)
#current_user.status!(2)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Request.find(params[:id]).requester
current_user.decline!(#user)
respond_to do |format|
format.html { redirect_to current_user }
format.js
end
end
When decline is clicked the request is removed from the database as well as from the user requests list. Which I need it also after accepting the request it should be removed from both the database and request list.
Can anyone help to achieve this?
Is it possible to call the destroy function after the accept button is clicked?
Or any other suggestions??
Answering to your question, YES we can call the destroy action. But I suggest we go with something more scale and pretty design, here is my rough design (not tested):
# routes.rb
Rails.application.routes.draw do
resources :requests, only: [] do
member do
patch :accept
patch :decline
end
end
end
# request.rb
class Request < ApplicationRecord
belongs_to :user
def accept
# 1. Do accept logic
# 2. Destroy
destroy
end
def decline
# 1. Do decline logic
# 2. Destroy
destroy
end
end
# requests_controller.rb
class RequestsController < ApplicationController
before_action :set_request
def accept
#request.accept
# Redirect somewhere
redirect_to profile_path
end
def decline
#request.decline
# Redirect somewhere
redirect_to profile_path
end
private
def set_request
#request = Request.find(params[:id])
end
end
With the following design you and add more logic easily to decline/accept e.g send email ...

Implement "add to favorites"

I am creating an app where a user can favorite a room. I started with a has_and_belongs_to_many association. But then I just noticed that it is very tricky to implement a remove button with drestroy. So I decided to do it this time with a has_many through association. I have a users who should add rooms to favorite or wishlist. Unfortunately when I click on the favorite button I am getting this error:
What I am missing how can I make this work?
If you need further information just let me know. I have used this as a direction.
Implement "Add to favorites" in Rails 3 & 4
favorite_room.rb
class FavoriteRoom < ApplicationRecord
belongs_to :room
belongs_to :user
end
room.rb
belongs_to :user
has_many :favorite_rooms
has_many :favorited_by, through: :favorite_rooms, source: :user
user.rb
has_many :rooms
has_many :favorite_rooms
has_many :favorites, through: :favorite_rooms, source: :room
routes.rb
resources :rooms do
put :favorite, on: :member
end
rooms_controller.rb
before_action :set_room, only: [:show, :favorite]
...
...
def favorite
type = params[:type]
if type == "favorite"
current_user.favorites << #room
redirect_to wishlist_path, notice: 'You favorited #{#room.listing_name}'
elsif type == "unfavorite"
current_user.favorites.delete(#room)
redirect_to wishlist_path, notice: 'Unfavorited #{#room.listing_name}'
else
# Type missing, nothing happens
redirect_to wishlist_path, notice: 'Nothing happened.'
end
end
private
def set_room
#room = Room.find(params[:id])
end
show.html.erb
<% if current_user %>
<%= link_to "favorite", favorite_room_path(#room, type: "favorite"), method: :put %>
<%= link_to "unfavorite", favorite_room_path(#room, type: "unfavorite"), method: :put %>
<% end %>
create_favorite_rooms.rb (migration file)
class CreateFavoriteRooms < ActiveRecord::Migration[5.0]
def change
create_table :favorite_rooms do |t|
t.integer :room_id
t.integer :user_id
t.timestamps
end
end
end

NoMethodError eventhough action is defined?

I am trying to build a website where a user can book a room. I have a working favorite feature but only if a user is logged in. If a visitor simply wants to view the show.html.erb of a single room I am getting this error:
I actually have defined favorite.
How can I make the visitors be able to view the show.html.erb of a single room?
rooms_controller.rb
before_action :set_room, only: [:show, :favorite]
...
...
def favorite
type = params[:type]
if type == "favorite"
current_user.favorites << #room unless current_user.favorites.exists?(#room)
redirect_to wishlist_path, notice: 'You favorited #{#room.listing_name}'
elsif type == "unfavorite"
current_user.favorites.delete(#room)
redirect_to wishlist_path, notice: 'Unfavorited #{#room.listing_name}'
else
# Type missing, nothing happens
redirect_to wishlist_path, notice: 'Nothing happened.'
end
end
private
def set_room
#room = Room.find(params[:id])
end
show.html.erb (room)
<% if current_user.favorites.exists?(#room) %>
<%= link_to "unfavorite", favorite_room_path(#room, type: "unfavorite"), method: :put %>
<% else %>
<%= link_to "favorite", favorite_room_path(#room, type: "favorite"), method: :put %>
<% end %>
I have a user, room and favorite_room model:
favorite_room.rb
belongs_to :room
belongs_to :user
user.rb
has_many :favorite_rooms # just the 'relationships'
has_many :favorites, through: :favorite_rooms, source: :room # the actual rooms a user favorites
room.rb
has_many :favorite_rooms # just the 'relationships'
has_many :favorited_by, through: :favorite_rooms, source: :user # the actual users favoriting a room
You can check if current_user is defined.
Try this code
<% if current_user && current_user.favorites.exists(#room) %>
# your if
<% else %>
# your else
<% end %>

Rails: Set up favorite recipe for user but keep getting same error

As a user I want to be able to add a recipe to my Favorites. Unfortunately when I try to add a recipe to my Favorites I get the following error: Recipe(#69883866963220) expected, got NilClass(#46922250887180).
I followed this 'tutorial' as a guideline
Somehow it is not able to add it to the user's Favorites. When I use Rails C and type in User.find(1).favorites, it returns me an empty array.
Who can help me to solve the issue? Thank you in advance!
My models:
class FavoriteRecipe < ActiveRecord::Base
belongs_to :recipe
belongs_to :user
end
class User < ActiveRecord::Base
has_many :recipes
# Favorite recipes of user
has_many :favorite_recipes # just the 'relationships'
has_many :favorites, through: :favorite_recipes, source: :recipe # the actual recipes a user favorites
end
class Recipe < ActiveRecord::Base
belongs_to :user
# Favorited by users
has_many :favorite_recipes # just the 'relationships'
has_many :favorited_by, through: :favorite_recipes, source: :user # the actual users favoriting a recipe
end
My recipecontroller.rb:
def show
#review = Review.new
#recipe = Recipe.find(params[:id])
#user = User.find(#recipe.user_id)
#full_name = #recipe.user.first_name + " " + #recipe.user.last_name
# #reviews = #recipe.reviews.page(params[:page]).order('created_at DESC')
end
# Add and remove favorite recipes
# for current_user
def favorite
type = params[:type]
if type == "favorite"
current_user.favorites << #recipe
redirect_to :back, notice: 'You favorited #{#recipe.name}'
elsif type == "unfavorite"
current_user.favorites.delete(#recipe)
redirect_to :back, notice: 'Unfavorited #{#recipe.name}'
else
# Type missing, nothing happens
redirect_to :back, notice: 'Nothing happened.'
end
end
Routes:
resources :recipes, only: [:index, :show] do
put :favorite, on: :member
end
My view: app/views/recipes/show.html.erb
<% if current_user.favorites.exists?(id: #recipe.id) %>
<%= link_to favorite_recipe_path(#recipe, type: "unfavorite"), method: :put do %>
<ul class="list-inline product-controls">
<li><i class="fa fa-heart"></i></li>
</ul>
<% end %>
<% else %>
<%= link_to favorite_recipe_path(#recipe, type: "favorite"), method: :put do %>
<ul class="list-inline product-controls">
<li><i class="fa fa-heart"></i></li>
</ul>
<% end %>
<% end %>
According to your relationship you need recipe object to assign to user. So need to first find that object and then assign it to user.
def favorite
#recipe = Recipe.find(params[:id])
type = params[:type]
if type == "favorite"
current_user.favorites << #recipe
redirect_to :back, notice: 'You favorited #{#recipe.name}'
elsif type == "unfavorite"
current_user.favorites.delete(#recipe)
redirect_to :back, notice: 'Unfavorited #{#recipe.name}'
else
# Type missing, nothing happens
redirect_to :back, notice: 'Nothing happened.'
end
end

Rails AJAX updating a nested model trouble

I have an app with the models Game, Square, Ownedsq, and User, and I am trying to update a square's :user_id within a game. I have been trying this for hours now, I believe the model relationships are correct and I am just missing something small so I appreciate any help.
Currently clicking the update ownedsq submit button does not change the user_id. There are no errors, nothing gets updated, nothing happens on the server.
games/show.html.erb
(Rows of 10 Ownedsq)
<div class="squareBoard">
<% #ownedsqs.each_slice(10) do |slice| %>
<div class='row'>
<% slice.each do |s| %>
<%= div_for s, class: 'sq' do |buy| %>
<%= s.user_id %>
<%= render "buyownedsq", s: buy %>
<% end %>
<% end %>
</div>
<% end %>
</div>
_buyownedsq.html.erb (clicking should set the ownedsq user_id to current user)
<%= simple_fields_for s, remote: true do |z| %>
<%= z.input :user_id, as: :hidden, input_html: {value:current_user.id} %>
<%= z.button :submit %>
<% end %>
games_controller.rb
def show
require 'enumerator'
#user = current_user
#game = Game.find(params[:id])
#squares = Square.all
#square = Square.find(params[:id])
#ownedsqs = Ownedsq.all
end
ownedsqs_controller.rb
def update
#ownedsq.find(params[:id])
respond_to do |format|
format.js
if #ownedsq.update_attributes(params[:ownedsq])
format.html {redirect_to game_path}
format.json {head :no_content}
else
format.html {redirect_to :back}
end
end
end
Game.rb
has_many :ownedsqs
has_many :squares, through: :ownedsqs
has_and_belongs_to_many :users
accepts_nested_attributes_for :ownedsqs
accepts_nested_attributes_for :squares
Square.rb
has_many :ownedsqs
has_many :users, through: :ownedsqs
has_many :games, through: :ownedsqs
accepts_nested_attributes_for :ownedsqs
accepts_nested_attributes_for :users
accepts_nested_attributes_for :games
Ownedsq.rb
belongs_to :square
belongs_to :user
belongs_to :game
validates_uniqueness_of :square_id, scope: :game_id
User.rb
has_and_belongs_to_many :games
has_many :ownedsqs
has_many :squares, through: :ownedsqs
accepts_nested_attributes_for :ownedsqs
accepts_nested_attributes_for :squares
Several problems here for you to look at:
How do you receive the params[:id] of the ownedsq?
You can easily get rid of the view-level user_id reference
Your remote calls won't raise an error directly; they'll do it through the network tab of your browser
Formatting
I'd just use a simple link / button to send the request to the server:
_buyownedsq.html.erb
<%= button_to ownedsq_path(buy.id), method: :put, data: {confirm: "Are you sure?"}, remote: :true %>
This will send a request to the server, which you can process like this:
#app/controllers/ownedsqs_controller.rb
def update
#ownedsq = Ownedsq.find(params[:id]) #where do you get the params[:id] var?
respond_to do |format|
format.js
if #ownedsq.update_attributes(user_id: current_user.id)
format.html {redirect_to game_path}
format.json {head :no_content, status: :200}
else
format.html {redirect_to :back}
format.json {status: :500 }
end
end
end
Save
Your associations look right - I don't presume the update_attributes method would get confused / have issues, as you're working directly with the OwnedSq model (not using accepts_nested_attributes_for etc)

Resources