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>
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'm trying to create an update form on Rails, for an object that has a foreignkey to another. However, it throws this error. I'm still very greenhorn with Ruby on Rails and have just been following a video tutorial, so I'm not quite sure how to interpret this. I am current using rails 5.0.0
In travelers_controllers.rb, below line
#prf = update_prof_params["profiles_attributes"]["0"]
throws the error
undefined method `[]' for nil:NilClass
edit.html.erb
<div class="col-md-7 col-md-offset-3 main">
<% provide(:title, "Edit user")%>
<center><h1>Update your profile</h1></center>
<%= form_for(#person) do |f| %>
<%= render 'shared/error_messages' %>
<div class="col-md-12">
<%= render 'layouts/profilefields', f: f %>
<%= f.submit "Save Changes", class: "btn btn-large btn-primary" %>
</div>
<% end %>
</div>
_profilefields.html.erb
<%= f.fields_for :profiles do |prf|%>
<!--
<% if !#profileInfo["avatar"].blank? %>
<%= image_tag #contactInfo.avatar_url(:medium).to_s, :class=>"profilePhoto" %>
<% end %>
<div class="photoPreview">
<i class="fa fa-upload photoUpload"></i>
<p id="uploadClick">Click to Upload</p>
</div>
<%= prf.file_field :avatar, accept: 'image/png,image/gif,image/jpeg, image/jpg', id: 'uploadAvatar' %>
<p class="deletePhoto">Delete</p>
-->
<%= prf.label :about %>
<%= prf.text_field :about, :class => "form-control" %>
<%= prf.label :why %>
<%= prf.text_field :why, :class => "form-control" %>
<%= prf.label :goals %>
<%= prf.text_field :goals, :class => "form-control" %>
<%= prf.hidden_field :traveler_id, value: current_traveler.id %>
<% end %>
travelers_controller.rb
class TravelersController < ApplicationController
def edit
#person = Traveler.find(params[:id])
#profileInfo = Profile.find_or_initialize_by(traveler_id: params[:id])
##profileInfo[:email] = current_traveler.email
#This builds the form
#person.build_profile(#profileInfo.attributes)
end
def show
end
def update
#prf = update_prof_params["profiles_attributes"]["0"]
#prof = Profile.find_or_create_by(traveler_id: current_traveler.id)
if #prof.update_attributes(prf)
flash[:success] = "Profile updated"
redirect_to feed_path
else # Failed. Re-render the page as unsucessful
render :edit
end
end
private
def update_prof_params
params.require(:traveler).permit(profiles_attributes: [:about, :why, :goals,
:traveler_id])
end
end
and the models
class Profile < ApplicationRecord
belongs_to :traveler, foreign_key: "traveler_id"
end
class Traveler < ApplicationRecord
# Include default devise modules. Others available are:
# , :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile
end
In TravelersController, the method update should be used for update traveler, not profile, so you can use mass-update via nested attribute like this:
def update
#traveler = Traveler.find(params[:id])
if #traveler.update(update_prof_params)
flash[:success] = "Profile updated"
redirect_to feed_path
else # Failed. Re-render the page as unsucessful
render :edit
end
end
So the above allow you to create/update profile which belongs to traveler. Besides, ensure the nested attribute was defined in your model:
traveler.rb
class Traveler < ActiveRecord::Base
# Your code here
#....
# Make sure define this
accepts_nested_attributes_for :profile
end
Update: The permitted params should be:
def update_prof_params
params.require(:traveler).permit(profile_attributes: [:about, :why, :goals, :traveler_id])
end
As you see profile_attributes should be used instead of profiles_attributes because traveler has one profile only
I'm trying to implement voting on comments within pits in my app and I keep getting a no method error. I've tried rearranging my code a number of different ways to get it to work but its not cooperating. My error in terminal shows this
Parameters: {"pit_id"=>"1", "comment_id"=>"2"}
Pit Load (0.2ms) SELECT "pits".* FROM "pits" WHERE "pits"."id" = ? LIMIT 1 [["id", 1]]
Completed 500 Internal Server Error in 2ms
NoMethodError (undefined method `comments' for nil:NilClass):
app/controllers/comments_controller.rb:22:in `upvote'
Its finding the "pit id" and the "comment id" but something is clearly a bit off. Would somebody with a better understanding of whats going on to point out what that it is. Thanks.
As it is now my code
_comment.html.erb
<div class = "well">
<p>
<strong>Comment:</strong>
<%= comment.body %>
<p>posted by: <%= comment.user.name %></p>
<%= link_to "Upvote", pit_comment_like_path(#pit, comment), method: :put, :remote => true %>
<%= link_to "Downvote", pit_comment_dislike_path(#pit, comment), method: :put, :remote => true %>
</p>
<p>
<%if comment.user == current_user %>
<%= link_to 'Destroy Comment', [#pit, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
</p>
</div>
Comments Controller
class CommentsController < ApplicationController
def create
#pit= Pit.find(params[:pit_id])
#comment = #pit.comments.build(comments_params)
#comment.user = current_user
#comment.save
redirect_to pit_path(#pit)
end
def destroy
#pit = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.destroy
redirect_to pit_path(#pit)
end
def upvote
#comment = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.upvote_by current_user
redirect_to pit_path(#pit)
end
def downvote
#comment = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.downvote_by current_user
redirect_to pit_path(#pit)
end
Routes
Rails.application.routes.draw do
devise_for :users, :controllers => { registrations: 'registrations' }
devise_scope :user do
get 'users/sign_in' => 'devise/sessions#new'
get 'users/sign_out' => 'devise/sessions#destroy'
match 'users/:id', to: 'users#show', as: 'user', via: 'get'
end
resources :pits do
resources :comments do
put "like", to: "comments#upvote"
put "dislike", to: "comments#downvote"
end
end
root to: 'pages#home'
get '/about' => 'pages#about'
end
User Class
class User < ActiveRecord::Base
acts_as_voter
has_many :pits
has_many :comments
enum role: [:user, :vip, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
def name
name = first_name + ' ' + last_name
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Comment Class
class Comment < ActiveRecord::Base
acts_as_votable
belongs_to :pit
belongs_to :user
end
I have a simple blog and I only want admin access to the create admin options and view. I have installed Devise and used authenticate_admin! in my controllers but when I test it out, the page is still accessible and allows anyone to sign out for admin options. I have limited options to the admin once signed in. The problem is that anyone can sign in. If I can basically just prevent access to the admin sign up page then I'm golden. At least in this case. I'm curious if somebody can point out my error or errors. Let me know if you need anything else. Thanks
class AdminsController < ApplicationController
before_action :authenticate_admin!
def index
end
def created
end
end
Articles Controller
class ArticlesController < ApplicationController
before_action :authenticate_admin!, :except => [:index, :show]
def new
#article = Article.new
end
def index
#article = Article.all
#articles = Article.order('created_at DESC')
#articles_by_month = Article.find(:all, :order => 'created_at DESC').group_by { |article| article.created_at.strftime("%B %Y") }
end
def month_count
#articles_by_month = Article.find(:all, :order => 'created_at DESC').group_by { |article| article.created_at.strftime("%B %Y") }
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def show
#article = Article.find(params[:id])
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text, :image)
end
end
Articles Index view
<div class="bit-75">
<% #article.each do |article| %>
<h2 id="title"><%= link_to article.title, article_path(article) %></h2>
<br>
<ul id="article-links">
<div id="article-image"><%= image_tag article.image_url %></div>
<br>
<li id="article-text"><%= article.text %></li>
<p>Posted on <%= article.created_at %></p>
<br>
<% if admin_signed_in? %>
<li><%= link_to 'Edit', edit_article_path(article) %></li>
<li><%= link_to 'Destroy', article_path(article),
method: :delete, data: { confirm: 'Are you sure?'} %></li>
<li><%= link_to 'New article', new_article_path %></li>
<% else %>
<li><%= link_to 'Make a Comment', article_path(article) %><p>Comments(<%= article.comments.count %>)</p></li>
</ul>
<% end %>
<% end %>
<div id="new-article-path"></div>
</div>
<div class="bit-5">
<h2>Recent Posts</h2>
<br>
<% #article.each do |article| %>
<ul id="recent-article">
<li><%= link_to article.title, article_path(article) %></li>
</ul>
<% end %>
<br>
<br>
<h2>Archives</h2>
<% #articles_by_month.each do |monthname, articles| %>
<h4 id="month-archive"><%=link_to monthname, archives_path %></h4>
<% end %>
<!-- <h2>Tags</h2> -->
</div>
Admin model
class Admin < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Article Model
class Article < ActiveRecord::Base
has_many :comments, dependent: :destroy
validates :title, presence: true,
length: { minimum: 5 }
mount_uploader :image, ImageUploader
default_scope -> { order('created_at DESC') }
end
Routes
Blog::Application.routes.draw do
devise_for :admins
devise_scope :admin do get "/admins/sign_out", to: 'devise/sessions#destroy'
end
devise_scope :admin do
get "/admins/sign_in", to: "devise/sessions#new"
end
devise_for :users
root 'articles#index'
resources :articles do
resources :comments
end
get "welcome/index"
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
match '/archives', to: 'archives#index', via: 'get'
You can remove registerable in your Admin model to prevent people from signing up as an admin:
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
but having devise_for :admins and then :users hints that it may be time for you to look into using a permission management gem like CanCanCan.
I made a website in which people can share photo's (they are called pins in my code). I wanted to add a system in which, when someone clicks on the picture, they can comment on it. I decided to use the commontator gem and I installed it. My problem is that the commenting system does not show up below posts like it's supposed to and I get an undefined local variable or method error for my pins controller.
routes.rb
Photo::Application.routes.draw do
resources :pins
devise_for :users
root "pins#index"
get "about" => "pages#about"
mount Commontator::Engine => '/commontator'
show.html.erb
<%= link_to 'Back', pins_path %>
<div class="row">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default">
<div class="panel-heading center">
<%= image_tag #pin.image.url(:medium) %>
</div>
<div class="panel-body">
<p><%= #pin.description %></p>
<p><strong><%= #pin.user.name if #pin.user %></strong></p>
<%= commontator_thread(commontable) %>
<% if #pin.user == current_user %>
<%= link_to edit_pin_path(#pin) do %>
<span class="glyphicon glyphicon-edit"></span>
<% end %>
<% end %>
</div>
</div>
</div>
pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
acts_as_commentable
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
validates :image, presence: true
acts_as_commontator
acts_as_commontable
end
pins_controller.rb
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#pins = Pin.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 8)
end
def show
end
def new
#pin = current_user.pins.build
end
def edit
end
def create
#pin = current_user.pins.build(pin_params)
if #pin.save
redirect_to #pin, notice: 'Pin was successfully created.'
else
render action: 'new'
end
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: 'Pin was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#pin.destroy
redirect_to pins_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
def correct_user
#pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "Not authorized to edit this pin" if #pin.nil?
end
def pin_params
params.require(:pin).permit(:description, :image)
end
end
User model user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins, dependent: :destroy
validates :name, presence: true
acts_as_commontator
end
error I am getting on show.html.erb
NameError in Pins#show
undefined local variable or method `commontable' for #<#<Class:0x007f9d8ccec328>:0x007f9d8df68768>
Extracted source (around line #12):
<div class="panel-body">
<p><%= #pin.description %></p>
<p><strong><%= #pin.user.name if #pin.user %></strong></p>
**<%= commontator_thread(commontable) %>**
<% if #pin.user == current_user %>
<%= link_to edit_pin_path(#pin) do %>
As there is no stacktrace added, a couple of observations.
acts_as_commontator and acts_as_commontable are added in same model.
As per documentation at https://github.com/lml/commontator
acts_as_commontator // to be added in user model(s) (or any models that should be able to post comments)
acts_as_commontable // to be added in models you want to be able to comment on
So can you try moving acts_as_commontator to user model?
In pin.rb line no. 3,.remove the line acts_as_commentable which is not used by your gem commontator
Assuming that you have added acts_as_commontable to the Pin model,
In the pins/show.html.erb,
Replace
<%= commontator_thread(commontable) %>
With
<%= commontator_thread(#pin) %>
As per the Commontator Usage Documentation,
In <%= commontator_thread(commontable) %>
commontable is an instance of a model that acts_as_commontable.
which in your case is #pin.