Hi I have a simple app with user, venue and heart models
User Model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :masqueradable, :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :omniauthable
has_many :hearts, dependent: :destroy
has_many :venues, through: :hearts
def hearts?(venue)
venue.hearts.where(user_id: id).any?
end
end
Venue Model
class Venue < ApplicationRecord
has_many :hearts, dependent: :destroy
has_many :users, through: :hearts
end
Heart Model
class Heart < ApplicationRecord
belongs_to :user
belongs_to :venue
validates :user_id, uniqueness: { scope: :venue_id }
end
The problem I have is that when I go to create a heart through the venue view I get the ActionController::RoutingError (No route matches [POST] "/venues/2/heart/2"):
app/views/venues/show.html.erb
<div class="row mb-3">
<div class="col text-center">
<h1><%= #venue.name %></h1>
</div>
</div>
<div class="row mb-3">
<div class="col text-center">
<%= render partial: 'heart', locals: {venue: #venue} %>
</div>
</div>
app/views/venues/_heart.html.erb
<% if user_signed_in? && current_user.hearts?(venue) %>
<%= link_to venue_heart_path(venue), method: :delete, remote: true do %>
<i class="fas fa-heart fa-2x" style="color: #cc0000"></i>
<% end %>
<% else %>
<%= link_to venue_heart_path(venue), method: :post, remote: true do %>
<i class="far fa-heart fa-2x" style="color: #cc0000"></i>
<% end %>
<% end %>
<p><%= venue.hearts.count %> <%= (venue.hearts.count) == 1 ? 'Heart' : 'Hearts'%></p>
<% #venue.hearts.each do |heart| %>
<%= image_tag heart.user.avatar_url, width: 20 %>
<% end %>
here is my controller for hearts and my routes|grep venue
app/controllers/venues/hearts_controller.rb
class Venues::HeartsController < ApplicationController
before_action :authenticate_user!
before_action :find_venue!
def create
#venue.hearts.where(user: current_user).first_or_create
redirect_to venue_path(#venue), :notice => 'Hearted!'
end
def destroy
#venue.hearts.where(user: current_user).destroy_all
redirect_to venue_path(#venue), :notice => 'UnHearted, you are heartless!'
end
private
def find_venue!
#venue = Venue.find(params[:venue_id])
end
end
rake routes | grep venue
warning ../package.json: No license field
venue_heart_index GET /venues/:venue_id/heart(.:format) venues/heart#index
POST /venues/:venue_id/heart(.:format) venues/heart#create
new_venue_heart GET /venues/:venue_id/heart/new(.:format) venues/heart#new
edit_venue_heart GET /venues/:venue_id/heart/:id/edit(.:format) venues/heart#edit
venue_heart GET /venues/:venue_id/heart/:id(.:format) venues/heart#show
PATCH /venues/:venue_id/heart/:id(.:format) venues/heart#update
PUT /venues/:venue_id/heart/:id(.:format) venues/heart#update
DELETE /venues/:venue_id/heart/:id(.:format) venues/heart#destroy
venues GET /venues(.:format) venues#index
POST /venues(.:format) venues#create
new_venue GET /venues/new(.:format) venues#new
edit_venue GET /venues/:id/edit(.:format) venues#edit
venue GET /venues/:id(.:format) venues#show
PATCH /venues/:id(.:format) venues#update
PUT /venues/:id(.:format) venues#update
DELETE /venues/:id(.:format) venues#destroy
config/routes.rb
require 'sidekiq/web'
Rails.application.routes.draw do
resources :venues do
resources :heart, module: :venues
end
I really appreciate your help
As the previous answer suggests, the path you're using in the link to create a new heart for a venue is not correct.
Have a look at the route for creating a heart. It seems like it has no prefix, but the same prefix as the route before (for heart#index) applies. So the link to create a new heart should have the venue_heart_index_path(venue).
I assume you didn't use resources in your routes.rb file?
ok so with the help of #arieljuod and #clara I was able to find my solution:
the problem stemmed from the follow along i was doing from here https://github.com/gorails-screencasts/gorails-24-liking-posts/blob/master/config/routes.rb
because i had resource and not resources rails asked for a singular on the create.
venue_heart_path didnt work, venue_heart_index_path threw a
ActionController::RoutingError (uninitialized constant Venues::HeartController
Did you mean? Venues::HeartsController): error
I went back to
<%= link_to venue_hearts_path(venue), method: :post, remote: true do %>
<i class="far fa-heart fa-2x" style="color: #cc0000"></i>
<% end %>
and changed the routes to
resources :venues do
resources :hearts, module: :venues
end
and the create worked... but the delete didnt. I had to change that to:
<%= link_to venue_heart_path(venue), method: :delete, remote: true do %>
<i class="fas fa-heart fa-2x" style="color: #cc0000"></i>
<% end %>
and boom it worked
You don't have a route with that format and POST method:
venue_heart GET /venues/:venue_id/heart/:id(.:format) venues/heart#show
PATCH /venues/:venue_id/heart/:id(.:format) venues/heart#update
PUT /venues/:venue_id/heart/:id(.:format) venues/heart#update
DELETE /venues/:venue_id/heart/:id(.:format)
Use PATCH por PUT methods instead to update an object.
Related
I'm making my first solo rails project. It's a facebook clone, and at the moment I can't get a user to accept a friend request. Please let me know if the information posted isn't sufficient enough to help work towards an answer.
friend_request_controller.rb
class FriendRequestsController < ApplicationController
before_action :set_friend_request, except: [:index, :create]
def index
#incoming = FriendRequest.where(friend: current_user)
#outgoing = current_user.friend_requests
end
def create
#user = User.find(current_user)
friend = User.find(params[:id])
#friend_request = current_user.friend_requests.new(friend_id: friend)
if #friend_request.save
redirect_to user_path(current_user)
end
end
def update
friend = User.find(params[:id])
#friend_request = current_user.friend_requests.find(friend_id: friend)
#friend_request.accept
end
show.html.erb
Hello my my email is <%= #user.email %>
<% if user_signed_in? %>
<li>
<%= link_to 'Logout', destroy_user_session_path, :method => :delete %></li>
<li><%= link_to 'All Users', users_path %>
</li>
<% else %>
<li>
<%= link_to('Login', new_user_session_path) %>
</li>
<% end %>
<ul>
<% current_user.friend_requests.each do |request| %>
<h4>You have new friend requests from:</h4>
<li>
<%= User.find(request.friend_id).email %>
<%= link_to "Accept", friend_request_path(friend_id: #friend),method:"put" %>
<%= link_to "Decline", "#" %>
</li>
<% end %>
</ul>
I know something is wrong with my link_to helper here
user.rb
class User < ApplicationRecord
has_many :friend_requests, dependent: :destroy
has_many :pending_friends, through: :friend_requests, source: :friend
has_many :friendships, dependent: :destroy
has_many :friends, through: :friendships
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
friend_request.rb
class FriendRequest < ApplicationRecord
belongs_to :user
belongs_to :friend, class_name: 'User'
def accept
user.friends << friend
destroy
end
def destroy
end
end
Do what #araratan has mentioned + in your frined_request controller, replace params[:id] with params[:friend_id].
Instead of:
<%= link_to "Accept", friend_request_path(friend_id: #friend),method:"put" %>
Try to change #friend to request.friend_id:
<%= link_to "Accept", friend_request_path(friend_id: request.friend_id),method:"put" %>
I installed Acts_as_follower. I used the methods from the documentation in my console so I've determined that user 1 follows user 2(using devise) in ActiveRecord, and on my front end in the users/show.html.erb page it shows the appropriate follow/unfollow portion of the button I've implemented. Unfortunately whenever I press the follow/unfollow button nothing changes or happens.
I'm thinking it's the routing but wondering if anybody has an idea of why nothing happens. I've confirmed the lack of action from my console.
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
acts_as_followable
acts_as_follower
has_attached_file :image, :styles => { :medium => "300x300>", :thumb=> "100x100>" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
has_many :articles
has_many :comments
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :articles do
member do
put "Like", to: "articles#upvote"
put "Disike", to: "articles#downvote"
end
resources :comments
end
resources :users do
get :follow
get :unfollow
end
root 'welcome#index'
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#user_articles = #user.articles
end
def create
#user = User.find(params[:user_id])
current_user.follow(#user)
end
def destroy
#user = User.find(params[:user_id])
current_user.stop_following(#user)
end
end
followers_controller.rb
class FollowsController < ApplicationController
before_action :authenticate_user!
respond_to :js
def create
#user = User.find(params[:user_id])
current_user.follow(#user)
end
def destroy
#user = User.find(params[:user_id])
current_user.stop_following(#user)
end
end
The button in users/show.html.erb
<div class="follow">
<% if #user.followed_by?(current_user) %>
<%= form_tag user_unfollow_path(user_id: #user.id), method: :post, remote: true do %>
<center><%= button_tag 'unfollow', class: 'btn btn-primary' %></center>
<% end %>
<% else %>
<%= form_tag user_follow_path(user_id: #user.id), method: :post, remote: true do %>
<center><%= button_tag 'follow', class: 'btn btn-success' %></center>
<% end %>
<% end %>
</div>
</div>
Your suspicion is correct, this is indeed a routing issue. But you get an A for effort as the documentation doesn't discuss the front end, good on you for getting this far :)
Your routes should look more like:
resources :users do
post :follow, to: "#followers#create"
delete :unfollow, to: "followers#destroy"
end
Note that unfollow is calling destroy, so by convention it's delete, also by convention create should be post.
Given that, make sure your view will look like:
<div class="follow">
<% if #user.followed_by?(current_user) %>
<%= form_tag user_unfollow_path(user_id: #user.id), method: :delete, remote: true do %>
<center><%= button_tag 'unfollow', class: 'btn btn-primary' %></center>
<% end %>
<% else %>
<%= form_tag user_follow_path(user_id: #user.id), method: :post, remote: true do %>
<center><%= button_tag 'follow', class: 'btn btn-success' %></center>
<% end %>
<% end %>
</div>
In my Rails App, I have a comment model ,a devise user model and a tales model. For each tales post , I have comments posted by signed-in users.The problem here is every other logged in user is able to delete the comments of other user.I want a functionality such that only the user who created the comments can delete it.
My user.rb is here
class User < ActiveRecord::Base
has_one :profile, dependent: :destroy
has_many :tales, dependent: :destroy
end
My comment.rb is here
class Comment < ActiveRecord::Base
belongs_to :tale
end
My tale.rb is here
class Tale < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
belongs_to :category
end
My routes.rb is as follows
Rails.application.routes.draw do
get 'tales/index'
devise_for :users, controllers: { registrations: "registrations" }
resources :profiles
resources :tales do
resources :comments
end
resources :categories
authenticated :user do
root "tales#index"
end
unauthenticated :user do
get "/" => "tales#index"
end
end
My comment controller is here:
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
#tale = Tale.find(params[:tale_id])
#comment = #tale.comments.create(comment_params)
redirect_to tale_path(#tale)
end
def destroy
#tale = Tale.find(params[:tale_id])
#comment = #tale.comments.find(params[:id])
#comment.destroy
end
private
def comment_params
params.require(:comment).permit(:name, :body, :tale_id)
end
end
The excerpt from my tales/show page to add comments is here:
<div id="comments">
<h2><%= #tale.comments.count %> Comments</h2>
<%= render #tale.comments %>
<h3>Add a comment:</h3>
<%= render "comments/form" %>
</div>
</div>
My _comment.html.erb is here
<div class="comment clearfix">
<div class="comment_content">
<p class="comment_name"><strong><%= comment.name %></strong></p>
<p class="comment_body"><%= comment.body %></p>
<p class="comment_time"><%= time_ago_in_words(comment.created_at) %>
Ago</p>
</div>
<% if user_signed_in? %>
<p><%= link_to 'Delete', [comment.tale, comment], method: :delete, data:
{ confirm: 'Are you sure?' } %></p>
<% end %>
</div>
I see no connection between user and comments and I dont the right way to do it here.Can someone guide me through this such that I can do so without using any gems .
You don't appear to have a relationship between Comment and User. You would need something like this in your Comment class assuming you are storing the user_id for each comment:
belongs_to :user
Then in your CommentsController your destroy method should be something like this:
def destroy
# Only the comments posted by that user will be returned
#comment = #user.comments.find(params[:id])
#comment.destroy
end
Add use_id in comments table if don't have
add_column :comments, :user_id, :integer
in your view file put following condition. Delete link will only visible to user who added comment.
<% if user_signed_in? && current_user.id == comment.user_id %>
<p><%= link_to 'Delete', [comment.tale, comment], method: :delete, data:
{ confirm: 'Are you sure?' } %></p>
<% end %>
I have this set up in my ActivitiesController:
class ActivitiesController < ApplicationController
def index
following_ids = current_member.following_members.map(&:id)
#activities = Activity.where("member_id in (?)", following_ids.push(current_member.id)).order("created_at desc")
end
end
This set up in my FollowsController:
def create
#member = Member.find_by_user_name(params[:member_id])
#follow_member = current_member.follow(#member)
if #follow_member
current_member.create_activity(#follow_member, 'followed')
respond_to do |format|
format.html { redirect_to #member }
format.js
end
end
end
And this set up to display the activity of following another member:
<div>
<span class="status_name">
<%= link_to activity.member.user_name, profile_path(activity.member) %>
</span>
<span>
is now following <%= link_to activity.targetable.following_member.user_name, "#" %>
</span>
<span class="meta">
<%= time_ago_in_words(activity.targetable.created_at) %>
</span>
</div>
<div class="act_content">
<%= follow_profile_link activity.targetable.following_member %>
</div>
I was able to get the following action to create a new activity item in the feed just fine but I can't figure out how to call to the member who's being followed. I get this error:
undefined method `following_member' for #<Follow:0x835b150>
app/views/activities/follow/_followed.html.erb:3:in `_app_views_activities_follow__followed_html_erb__269116874_68857716'
app/views/activities/index.html.erb:14:in `block in _app_views_activities_index_html_erb___16061925_44845644'
app/views/activities/index.html.erb:5:in `_app_views_activities_index_html_erb___16061925_44845644'
I can't figure out what I need to do or what specifically to call to make this work. Any ideas?
EDIT - Models
Activity Model
class Activity < ActiveRecord::Base
belongs_to :member
belongs_to :targetable, polymorphic: true
end
Follow Model
class Follow < ActiveRecord::Base
extend ActsAsFollower::FollowerLib
extend ActsAsFollower::FollowScopes
# NOTE: Follows belong to the "followable" interface, and also to followers
belongs_to :followable, :polymorphic => true
belongs_to :follower, :polymorphic => true
def block!
self.update_attribute(:blocked, true)
end
end
Member Model
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :email_confirmation, :password, :password_confirmation, :remember_me,
:first_name, :last_name, :user_name, :pursuits, :avatar, :bio, :city, :state, :country, :pursuit_list
has_many :medium
has_many :statuses
has_many :activities
acts_as_follower
acts_as_followable
acts_as_ordered_taggable
acts_as_ordered_taggable_on :pursuits
def create_activity(item, action)
activity = activities.new
activity.targetable = item
activity.action = action
activity.save
activity
end
Edit - Activities Migration
class CreateActivities < ActiveRecord::Migration
def change
create_table :activities do |t|
t.integer :member_id
t.string :action
t.integer :targetable_id
t.string :targetable_type
t.timestamps
end
add_index :activities, :member_id
add_index :activities, [:targetable_id, :targetable_type]
end
end
Activity Index
<% #activities.each do |activity| %>
<div class="status">
<div class="row">
<div class="span1 stream_av">
<%= avatar_profile_link activity.member %>
</div>
<div class="span7">
<%= render partial: "activities/#{activity.targetable_type.underscore}/#{activity.action}",
locals: { activity: activity } %>
</div>
</div>
</div>
<% end %>
New activity for uploading media
<div>
<span class="status_name">
<%= link_to activity.member.user_name, profile_path(activity.member) %></span> <span>uploaded new <%= link_to "Media", profile_media_path(activity.member) %></span> <span class="meta"> <%= time_ago_in_words(activity.targetable.created_at) %>
</span>
</div>
<div class="act_content">
<%= link_to image_tag(activity.targetable.asset.url(:medium), class: ''), medium_path(activity.targetable_id) %>
</div>
New activity for writing a status
<div>
<span class="status_name">
<%= link_to activity.member.user_name, profile_path(activity.member) %></span> <span>wrote a <%= link_to "Post", profile_stream_path(activity.member) %></span> <span class="meta"> <%= time_ago_in_words(activity.targetable.created_at) %>
</span>
</div>
<div class="act_content">
<%= activity.targetable.content %>
</div>
following_member returns an ActiveRecord object. So, you gotta do something like:
activity.targetable.following_member.first.user_name
instead of
activity.targetable.following_member.user_name
If you want to retrieve all the following members, you'll have to iterate through it.
<%activity.targetable.following_member.each do |member| %>
<%=member.user_name%>
<%end%>
The views I have created previously are all working fine. I generated a model and controller for subscriptions and have the corresponding views linked to my home page. No error is thrown, but my erb code isn't being rendered to my browser. I can add html (i.e. 'hello world' wrapped in div's).
I've tried the following.
Stripped the surrounding html code and just tried rails helper methods wrapped in erb.
Deleted and re-generated both Subscription model and subscriptions controller/views
Checked my routes.rb file for subscription-related issues
Looked at both of these related questions from SO to no avail. link1
link2
Here is a look at my code and output from webrick:
webrick output
# subscriptions/index.html.erb
<% form_for(#subscription) do |f| %>
<div class="container">
<div class="row-fluid">
<div class="span12">
<div class="widget widget-table">
<div class="widget-header">
<h3>
<i class="icon-"></i> Pay with Credit Card
</h3>
</div>
<div class="widget-content">
<table class="table table-striped table-bordered">
<tbody>
<tr>
<td>
<% if #subscription.stripe_card_token.present? %>
Credit card has been provided.
<% else %>
<div class="control-group">
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil %>
</div>
</td>
</tr>
<tr>
<td>
<div class="control-group">
<%= label_tag :card_code, "Security Code on Card (CVV)" %>
<%= text_field_tag :card_code, nil, name: nil %>
</div>
</td>
</tr>
<tr>
<td>
<div class="control-group">
<%= label_tag :card_month, "Card Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
</div>
</td>
<% end %>
</tr>
<tr>
<td>
<div id="stripe_error">
<noscript><!--Error here--></noscript>
</div>
</td>
</tr>
</tbody>
</table>
</div><!-- END CLASS widget-content -->
</div><!-- END CLASS widget widget-table -->
</div><!-- END CLASS span12 -->
</div><!-- END CLASS row-fluid -->
</div><!-- END CLASS container -->
<% end %>
# routes.rb
Whizcharts::Application.routes.draw do
resources :subscriptions, only: [:new, :create, :index]
# START devise routes
devise_for :admins, controllers: { registrations: "registrations" }# , path_names: { sign_in: "login", sign_out: "logout" }
mount Deviseadmin::Engine, at: "/deviseadmin"
devise_for :users, path_names: { sign_in: "login", sign_out: "logout" }
## END devise routes
# START mailer
# match 'admins/show', to: "admins#show"
## END mailer
# START static_pages routes
root to: "static_pages#home"
match "static_pages/about", to: "static_pages#about", as: :about
match "static_pages/pricing", to: "static_pages#pricing", as: :pricing
match "static_pages/contact", to: "static_pages#contact", as: :contact
## END static_pages routes
# START deployments routes
match "deployments/deployment_print", to: "residents#deployment_print", as: :print
# subscriptions_controller.rb
# Note: Subscription.new is in the index method temporarily to demonstrate this issue
class SubscriptionsController < ApplicationController
def index
#subscription = Subscription.new
#subscriptions = Subscription.all
end
def new
#subscription = Subscription.new
end
def show
#subscription = Subscription.find(params[:id])
end
end
# subscription.rb
class Subscription < ActiveRecord::Base
belongs_to :admin, dependent: :destroy
validates_presence_of :plan_id
attr_accessor :stripe_card_token
def save_with_payment
if valid?
customer = Stripe::Customer.create(plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
end
# admin.rb
# Note: Included to demonstrate the association between the Admin and Subscription models
class Admin < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :fac_name, :fac_address, :fac_city, :fac_state, :fac_zip, :lic_num, :owner_fname, :owner_lname, :fac_phone1,:fac_phone2, :fac_phone3, :fac_phone4, :fac_phone5, :fac_email1, :fac_email2, :fac_email3, :fac_email4, :fac_email5, :initials
has_many :residents
has_many :fund_record_form2s, through: :residents
has_many :deployments
has_many :subscriptions
def full_name
"#{owner_fname} #{owner_lname}"
end
end
I am running rails 3.2.14
If I forgot something, I will put it up promptly after your notification.
You are missing the equal(=) sign.
It should be <%= form_for(#subscription) do |f| %>
You are missing the equal sign before the form_for helper.
<%= form_for %>
You need the equal sign, otherwise the ERB tags are not put on the template.