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 %>
Related
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 ...
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
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
I have three models: User, Publisher and Interest all with many to many relationships linked through three join models but only 2 out of 3 join models record the id's of their 2 parent models. my UsersPublisher model does not link User to Publisher.
My Interestscontroller proccesses a form (see code) through which I ask the user to provide Interest and Publisher. The latter gets processed via the fields_for method which allows you to pass Publisher attributes via the InterestsController. the UsersPublisher join model records the user_id but the publisher_id is nil.
I've tried putting #users_publishers in both the new and create methods of Publishers- and InterestsController. My latest attempt of using after_action in the InterestsController (see code) has also failed. I've also tried the after_action way in the PublishersController
Your helped is highly appreciated!
The UsersPublisher join model
class UsersPublisher < ActiveRecord::Base
belongs_to :user
belongs_to :publisher
end
InterestsController
class InterestsController < ApplicationController
before_action :find_user
after_action :upublisher, only: [:new]
def index
#interests = policy_scope(Interest)
end
def show
#interest = Interest.find(params[:id])
end
def new
#interest = Interest.new
#interest.publishers.build
authorize #interest
end
def create
#interest = Interest.new(interest_params)
#users_interests = UsersInterest.create(user: current_user, interest: #interest)
authorize #interest
if #interest.save
respond_to do |format|
format.js
format.html {redirect_to root_path}
end
flash[:notice] = 'Thank you, we will be in touch soon'
else
respond_to do |format|
format.js { render }
format.html { render :new }
end
end
end
def edit
#interest = Interest.find(params[:id])
authorize #interest
end
def update
#interest = Interest.find(params[:id])
#interest.update(interest_params)
if #interest.save
flash[:notice] = 'Your interest has been added'
else
flash[:notice] = 'Oops something went wrong'
end
end
private
def interest_params
params.require(:interest).permit(:name, publishers_attributes: [:publisher,:id, :feed])
end
def find_user
#user = current_user
end
def upublisher
#users_publishers = UsersPublisher.create(publisher: #publisher, user: current_user)
end
end
Form
<%= form_for [#user, #interest] do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :publishers do |ff| %>
<%= ff.label :publisher %>
<%= ff.text_field :publisher %>
<%= ff.label :feed %>
<%= ff.text_field :feed %>
<%end%>
<%= f.submit "Submit" %>
<%end%>
Since you're using fields_for, you'll want to make sure you have accepts_nested_attributes_for:
class UsersPublisher < ActiveRecord::Base
belongs_to :user
belongs_to :publisher
accepts_nested_attributes_for :publisher
end
This should fix your issue (if it's as you outlined).
Your question is pretty broad, so I don't know whether the above will work. Below are my notes...
From the looks of it, your structure is very complicated; you should work to make it as simple as possible. In the case of creating "interests", you may wish to get rid of the form completely:
#config/routes.rb
resources :publishers do
resources :interests, path: "interest", only: [:create, :destroy] #-> url.com/publishers/:publisher_id/interest
end
#app/controllers/interests_controller.rb
class InterestsController < ApplicationController
before_action :set_publisher
def create
current_user.interests.create publisher: #publisher
end
def destroy
#interest = current_user.interests.find_by publisher_id: #publisher.id
current_user.interests.delete #interest
end
private
def set_publisher
#publisher = UserPublisher.find params[:publisher_id]
end
end
You'd be able to use the above as follows:
<%= link_to "Add Interest", publisher_interest_path(#publisher), method: :post %>
<%= link_to "Remove Interest", publisher_interest_path(#publisher), method: :delete %>
Thinking about it properly, you've got a pretty bad structure.
I'd do something like this:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :interests
has_many :publishers, through: :interests
end
#app/models/interest.rb
class Interest < ActiveRecord::Base
belongs_to :user
belongs_to :publisher
accepts_nested_attributes_for :publisher
end
#app/models/publisher.rb
class Publisher < ActiveRecord::Base
has_many :interests,
has_many :users, through: :interests
end
This should give you the ability to create interests for any number of users and publishers. If you create a publisher for a specific user, you can use accepts_nested_attributes_for to pass the appropriate data:
#config/routes.rb
resources :users do
resources :interest, only: [:new, :create, :destroy] #-> url.com/users/:user_id/interests/new
end
#app/controllers/interests_controller.rb
class InterestsController < ApplicationController
def new
#user = User.find params[:user_id]
#interest = #user.interests.new
#interest.publisher.build
end
def create
#user = User.find params[:user_id]
#interest = #user.interests.new interest_params
end
private
def interest_params
params.require(:interest).permit(:user, :publisher)
end
end
#app/views/interests/new.html.erb
<%= form_for [#user, #interest] do |f| %>
<%= f.fields_for :publisher do |p| %>
<%= p.text_field :name %>
<% end %>
<%= f.submit %>
<% end %>
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 %>