I am trying to create a posts pages. Where users can see all the public posts. I can successfully create posts but I can't see them.
ActionController::UrlGenerationError in Ribbits#index Showing
C:/Sites/myBlog/app/views/ribbits/index.html.erb where line #8
raised:
No route matches {:action=>"show", :controller=>"users", :id=>nil}
missing required keys: [:id]
The index.html.erb
<% #ribbits.each do |ribbit| %>
<div class="ribbitWrapper">
<a href="<%= user_path ribbit.user %>">
<img class="avatar" src="<% ribbit.user.avatar_url %>" />
<span class="name"> <%= ribbit.user.name %> </span>
</a>
#<%= ribbit.user.username %>
<span class="time"><%= time_ago_in_words(ribbit.created_at) %></span>
<p> <%= ribbit.content %></p>
</div>
<% end %>
The users controller:
def new
#user = User.new
end
def create
#user = User.create(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to #user, notice: "Thank you for signing up!"
else
render 'new'
end
end
def show
#user = User.find(params[:id])
#ribbit = Ribbit.new
end
The ribbits controller
def index
#ribbits = Ribbit.all
#ribbit = Ribbit.new
end
def create
#ribbit = Ribbit.create(user_ribbits)
#ribbit.user_id = current_user.id
if #ribbit.save
redirect_to current_user
else
flash[:error] = "Problem!"
redirect_to current_user
end
end
private
def user_ribbits
params.require(:ribbit).permit(:content, :userid)
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
And also, the routes file
resources :sessions
resources :users
resources :ribbits
get 'logout', to: 'sessions#destroy', as: 'logout'
root to: 'users#new'
Would really appreciate the help!
As we discovered in the comments to the question, some of the #ribbits do not have user_id set.
To address your further question of "How do I connect user_id with my ribbits, my guess is that you have ribbits with user_id null because your user_ribbits method permits :userid rather than :user_id. This is assuming of course that you're properly passing user_id from your view to your controller on the creation of a ribbit.
In order to ensure that ribbits contain a user_id, you can add the following to your Ribbit model (ribbit.rb):
validates :user_id, presence: true
If there are other issues, this should at the very least prevent you from creating a ribbit without a user_id.
I hope this helps!
Related
I am building a simple blog app using Ruby on Rails that allows users to log in/out, sign up and perform actions on their articles and profiles based on permissions and restrictions.
I have encountered a problem with the destroy User action. In the users/index view(where all existing users are listed), it causes no errors due to the url path containing no {:id}, but the redirect_to root_path does not work. If the same action is executed in the users/show page(personal profile page with some info and associated articles), due to the url being localhost/users/id, when the user is deleted I get "Couldn't find User with 'id'=33" error shown below. If I manually go to the root route, the successful account deletion message shows up and the action is performed correctly. So this is not a metter of DESTROY not working, but of redirection I believe. I have tried redirecting to different paths but it still doesn't work. Here are the related files:
routes.rb
Rails.application.routes.draw do
root "pages#home"
get "about", to: "pages#about"
resources :articles
get "signup", to: "users#new"
resources :users, except: [:new]
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
get 'logout' => :destroy, to: 'sessions#destroy'
end
pages_controller
class PagesController < ApplicationController
def home
redirect_to articles_path if logged_in?
end
def about
end
end
users_controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_action :require_user, only: [:edit, :update]
before_action :require_same_user, only: [:edit, :update, :destroy]
def index
#users = User.all
end
def show
#articles = #user.articles
end
def new
#user = User.new
end
def edit
end
def create
#user = User.new(user_params)
if(#user.save)
session[:user_id] = #user.id #logs user in automatically once they are signed up
flash[:notice] = "Welcome to AlphaBlog, #{#user.username}!"
redirect_to articles_path
else
render 'new'
end
end
def update
if #user.update(user_params)
flash[:notice] = "Account updated!"
redirect_to #user
else
render 'edit'
end
end
def destroy
#user.destroy
session[:user_id] = nil
flash[:notice] = "Account and all associated articles deleted!"
redirect_to root_path
end
private
def user_params
params.require(:user).permit(:username, :email, :password)
end
def set_user
#user = User.find(params[:id])
end
def require_same_user
if current_user != #user
flash[:alert] = "You can only edit your own profile!"
redirect_to current_user
end
end
end
sessions_controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
session[:user_id] = user.id
flash[:notice] = "Logged in successfully!"
redirect_to user
else
flash.now[:alert] = "There was something wrong with your login details!"
render 'new'
end
end
def destroy
session[:user_id] = nil
flash[:notice] = "Logged out."
redirect_to root_path
end
end
users/index.html.erb
<div class = "header">
<h1>
AlphaBlog
<% if logged_in? %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<% else %>
<%= link_to 'Home', root_path(), method: :get, class: "index-button-to" %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<% end %>
<%= render 'layouts/log_in_out_navigation'%>
</h1>
</div>
<h2>Alpha Bloggers</h2>
<div class="index-container">
<%# cycle through all articles and show them all in a table %>
<% #users.each do |user| %>
<div class = "index-article-container">
<div class="index-article-user" style = "color:rgb(16, 136, 255);">
<%= user.username %>
</div>
<div class="white">
<div class="index-article-title">
<%= gravatar_for(user, size: 150) %>
</div>
<div class="index-article-description">
<%# gives the plural word for multiple articles %>
<%= pluralize(user.articles.count, "article") %>
</div>
<div class="index-article-actions">
<%# shows selected article page %>
<%= link_to 'View Profile', user, class: "index-link-to show" %>
<% if logged_in? && current_user.username == user.username %>
<%# shows selected article EDIT page. edit_article_path because in routes,
the prefix for edit is edit_article && (article) because we need the id for the path as well%>
<%= link_to 'Edit Profile', edit_user_path(user), data: { turbo_method:
:get}, class: "index-link-to edit" %>
<%= link_to 'Delete Profile', user_path(current_user), data: {
turbo_method: :delete, turbo_confirm: "Are you sure? (This will also delete all of your
articles)" }, class: "index-link-to delete" %>
<% end %>
</div>
</div>
<div class="index-created-updated">
Joined <%= time_ago_in_words(user.created_at) %> ago.
</div>
</div>
<% end %>
users/show.html.erb
<div class = "header">
<h1>
AlphaBlog
<% if logged_in? %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<%= link_to 'Bloggers', users_path, method: :get, class: "index-button-to" %>
<% else %>
<%= link_to 'Home', root_path(), method: :get, class: "index-button-to" %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<%= link_to 'Bloggers', users_path, method: :get, class: "index-button-to" %>
<% end %>
<%= render 'layouts/log_in_out_navigation'%>
</h1>
</div>
<h2> <%= #user.username %>'s profile </h2>
<div class="show-users-image">
<%# gravatar_for method created in helpers/application_helper %>
<%= gravatar_for #user, size: 200 %>
<% if logged_in? && current_user.username == #user.username %>
<div class="index-profile-actions">
<%= link_to "Edit Profile", edit_user_path(#user), class: "index-link-to edit" %>
<%= link_to 'Delete Profile', user_path(current_user), data: { turbo_method: :delete,
turbo_confirm: "Are you sure? (This will also delete all of your articles)" }, class: "index-
link-
to delete", style: "margin-top:0.3vh" %>
</div>
<% end %>
</div>
<h3 style = "text-align:center">Articles</h3>
<%= render 'articles/article' %>
error page
The way to do this in Rails 7 is to update the destroy action in the UsersController by adding status: :see_other after the redirect, as follows:
def destroy
#user.destroy
session[:user_id] = nil
flash[:notice] = "Account and all associated articles deleted!"
redirect_to root_path, status: :see_other
end
I think the answer here is really a very different layout of your routes and controller (or to not reivent the wheel in the first place). Passing the user id through the parameters would be fine if your making a system where you are managing other users - but its pretty wonky when users are managing their own profiles.
For example this is how users CRUD their own profiles in a vanilla Devise setup:
Verb URI Pattern Controller#Action
------------------------------------------------------------------------
GET /users/cancel(.:format) devise/registrations#cancel
GET /users/sign_up(.:format) devise/registrations#new
GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
Note the lack of the :id parameter in the URI Pattern. Thats because its implied that the resource in question is the currently signed in user, and that the user is identified through the session (or a token).
The controller is named Registrations to avoid the ambiguity if the programmer later wants to add a UsersController to manage other users.
If you want to do something similiar you can generate singular routes by using the resource macro instead of resources.
# routes for user registration
resource :registrations,
only: [:new, :edit, :update, :create, :destroy]
# routes for viewing other users
resources :users, only: [:index, :show]
Which will generate:
Prefix Verb URI Pattern Controller#Action
-----------------------------------------------------------------------
new_registrations GET /registrations/new(.:format) registrations#new
edit_registrations GET /registrations/edit(.:format) registrations#edit
registrations GET /registrations(.:format) registrations#show
PATCH /registrations(.:format) registrations#update
PUT /registrations(.:format) registrations#update
DELETE /registrations(.:format) registrations#destroy
POST /registrations(.:format) registrations#create
Name it whatever you want. The core takeaway here is to not confuse two completely different problems - user management and user registrations and have separate endpoints and controllers for each responsibilty.
Then in your controller you simply authenticate the user from the session and redirect the user if they are not authenticated:
# Handles user account registration, updates and deleting accounts
class RegistrationsController < ApplicationController
before_action :require_user, except: [:new, :create]
# Displays the form for signing up a user
# GET /registrations
def new
#user = User.new
end
# Register a new user and sign them in
# POST /registrations
def create
#user = User.new(user_params)
if #user.save
reset_session # avoids session fixation attacks
session[:user_id] = #user.id #logs user in automatically once they are signed up
flash[:notice] = "Welcome to AlphaBlog, #{#user.username}!"
redirect_to articles_path
else
render :new
end
end
# Form for editing the users own profile
# GET /registrations/edit
def edit
#user = current_user
end
# Update the currently signed in user
# PATCH /registrations
def update
#user = current_user
if #user.update(user_params)
flash[:notice] = "Account updated!"
redirect_to current_user
else
render :new
end
end
# Cancel the current users registration
# DELETE /registrations
def delete
current_user.delete
reset_session # avoids session fixation attacks
flash[:notice] = "Account and all associated articles deleted!"
redirect_to root_path
end
private
def user_params
params.require(:user).permit(:username, :email, :password)
end
end
# Displays users
# Managing accounts is handled by RegistrationsController
class UsersController < ApplicationController
# GET /users
def index
#users = User.all
end
# GET /users/1
def show
#user = User.find(params[:id])
#articles = #user.articles
end
end
Since their is no id in the path you you need to set the delete button to send to the right path:
<%= button_to "Delete your account", registrations_path, method: :delete %>
And adjust your forms:
<%= form_with(model: #user, url: registrations_path) do |form| %>
# ...
<% end %>
Doing this the correct way would really be to do it the same way that Devise does and have a normal link that sends a GET request to a "Are you sure you want to delete your account?" page when then requires the user to enter their password or email and submits a DELETE request so that users don't accidentially delete their accounts.
But then again don't reinvent the authentication wheel unless you want a long and tedious lesson into wheelmaking.
I'm not sure you have truly got to the bottom of this. In your original approach I suspect two things are going on:
In users/index.html.erb you have link_to 'Delete Profile', user_path(current_user) but I think you want user_path(user). What you currently have will have every delete button try to delete the same user.
The fact that error says your are attempting to execute 'show' rather than 'destroy' makes me suspect that you do not have turbo loaded properly. You don't say what version of rails you are using, but for versions earlier than 7 you don't get turbo out of the box, and you should use UJS instead.
compare this https://guides.rubyonrails.org/getting_started.html#deleting-an-article with this https://guides.rubyonrails.org/v6.1/getting_started.html#deleting-an-article
I am using nested resources. When I click on a goal that's been created, I keep getting this error:
param is missing or the value is empty: goal
And it directs me to the "params.require..." line:
private
def goal_params
params.require(:goal).permit(:text)
end
I'm not sure what's causing this. I can create and show the list. But when I click on a goal I get this error. I'm new to rails and I'm at my wit's end.
My view:
<h1>Listing goals</h1>
<table>
<tr>
<th>Text</th>
<th></th>
</tr>
<% #user.goals.each do |goal| %>
<tr>
<td><%= link_to goal.text, user_goals_path(#user, #goal)%></td>
</tr>
<% end %>
</table>
<h2>Add a comment:</h2>
<%= form_for([#user, #user.goals.build]) do |form| %>
<p>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
My controller:
class GoalsController < ApplicationController
def index
#user = User.find(params[:user_id])
#goal = #user.goals.find(goal_params)
end
def show
#user = User.find(params[:user_id])
#goal = #user.goals.find(:id)
#also tried goal_params and :goal_id instead of :id
end
def new
#user = User.find(params[:user_id])
#goal = #user.goals.new
end
def create
#user = User.find(params[:user_id])
#goal = #user.goals.build(goal_params)
#goal.user = current_user
if #goal.save
redirect_to new_user_goal_path, notice: "Success!~"
else
redirect_to new_user_goal_path, alert: "Failure!"
end
#to root_path
end
private
def goal_params
params.require(:goal).permit(:text)
end
end
My routes:
Rails.application.routes.draw do
devise_for :users
resources :user do
resources :goals
end
devise_scope :user do
authenticated :user do
root 'home#index', as: :authenticated_root
end
unauthenticated do
root 'devise/sessions#new', as: :unauthenticated_root
end
end
end
My show.html.erb:
<p>
<strong>Text:</strong>
<%= #goal.text %>
</p>
First thing, in the show
#goal = #user.goals.find(:id)
Should be
#goal = #user.goals.find(params[:id])
You said you tried with #user.goals.find(goal_params) in show action and I see it in your index action also. This will call the goal_params method, which require params[:goal] while your index or show request does not send to server, only when you submit the form, you will have that params. This is the cause of your error.
Second thing, your index should use
#goals = #user.goals
INSTEAD OF
#goal = #user.goals.find(goal_params)
Also, the strong parameters is used for create and update actions only to avoid mass assignment to our database. It's not used to find a record.
I'm building an Events app and I'm trying to create a link from the Event show page to the event creator's profile but I'm getting the following error -
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with 'id'=21
The error highlights this particular line of code in the Users Controller -
def show
#user = User.find(params[:id])
end
The development log produces this output -
Started GET "/users/21" for ::1 at 2016-04-15 12:37:08 +0100
Processing by UsersController#show as HTML
Parameters: {"id"=>"21"}
[1m[36mUser Load (0.1ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1[0m [["id", 8]]
[1m[35mUser Load (0.2ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 21]]
Completed 404 Not Found in 14ms (ActiveRecord: 0.9ms)
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=21):
app/controllers/users_controller.rb:14:in `show'
The user id (in this instance 5) is not being passed.I've tried numerous arguments in the show.html.erb page but none will work. Changing the show argument in the users controller to #user = current_user only succeeds in bringing up the profile of the user viewing the event and not the profile of the event creator.
Here's my code -
Events Controller
class EventsController < ApplicationController
before_action :find_event, only: [:show, :edit, :update, :destroy,]
# the before_actions will take care of finding the correct event for us
# this ties in with the private method below
before_action :authenticate_user!, except: [:index, :show]
# this ensures only users who are signed in can alter an event
def index
if params[:category].blank?
#events = Event.all.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#events = Event.where(category_id: #category_id).order("created_at DESC")
end
# The above code = If there's no category found then all the events are listed
# If there is then it will show the EVENTS under each category only
end
def show
end
def new
#event = current_user.events.build
# this now builds out from a user once devise gem is added
# after initially having an argument of Event.new
# this assigns events to users
end
# both update and create actions below use event_params as their argument with an if/else statement
def create
#event = current_user.events.build(event_params)
# as above this now assigns events to users
# rather than Event.new
if #event.save
redirect_to #event, notice: "Congratulations, you have successfully created a new event."
else
render 'new'
end
end
def edit
# edit form
# #edit = Edit.find(params[:id])
#event = current_user.events.find(params[:id])
end
def update
if #event.update(event_params)
redirect_to #event, notice: "Event was successfully updated!"
else
render 'edit'
end
end
def destroy
#event.destroy
redirect_to root_path
end
private
def event_params
params.require(:event).permit(:title, :location, :date, :time, :description, :number_of_spaces, :is_free, :price, :organised_by, :organiser_profile, :url, :image, :category_id)
# category_id added at the end to ensure this is assigned to each new event created
end
def find_event
#event = Event.find(params[:id])
end
end
Users Controller -
class UsersController < ApplicationController
before_action :authenticate_user!
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = "Welcome to Mama Knows Best"
session[:uid] = #user.id
redirect_to root_path
else
render 'new'
end
end
def edit
#user = current_user
end
def update
#user = current_user
if #user.update(user_params)
flash[:success] = "Profile successfully updated!"
redirect_to root_path
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :username, :biography, :email, :url)
end
end
Show page -
<%= image_tag #event.image.url %>
<h1><%= #event.title %></h1>
<p>Location </p>
<p><%= #event.location %></p>
<p>Date</p>
<p><%= #event.date.strftime('%A, %d %b %Y') %></p>
<p>Time</p>
<p><%= #event.time.strftime('%l:%M %p') %></p>
<!-- above expresses date and time as per UK expectations -->
<p>More details</p>
<p><%= #event.description %></p>
<p>Number of Spaces available</p>
<p><%= #event.number_of_spaces %></p>
<% if #event.is_free? %>
<p>This is a free event</p>
<% else %>
<p>Cost per person</p>
<p><%= #event.price %></p>
<% end %>
<p>Organiser</p>
<p><%= #event.organised_by %></p>
<p>Organiser Profile</p>
<button><%= link_to "Profile", user_path %></button>
<p>Link to Organiser site</p>
<button><%= link_to "Organiser site", #event.url %></button>
<p>Submitted by</p>
<p><%= #event.user.name %></p>
<% if user_signed_in? and current_user == #event.user %>
<%= link_to "Edit", edit_event_path %>
<%= link_to "Delete", event_path, method: :delete, data: { confirm: "Are you sure?"} %>
<%= link_to "Back", root_path %>
<% else %>
<%= link_to "Back", root_path %>
<%= link_to "Book the Event", new_event_booking_path(#event) %>
<% end %>
routes -
Rails.application.routes.draw do
devise_for :users, :controllers => { registrations: 'registrations' }
resources :users
resources :events do
resources :bookings
end
# get 'welcome/index'
authenticated :user do
root 'events#index', as: "authenticated_root"
end
root 'welcome#index'
# the above method comes from devise and allows for the site to have a home page
# for users not signed in and one for when they are signed in
end
I haven't added anything relating to the users profile on the form partial as I didn't believe it to be relevant. Any help would be much appreciated.
To reiterate your question, you want a link on the event page that goes to the event organiser's profile page?
<p>Organiser Profile</p>
<button><%= link_to "Profile", user_path(#event.user) %></button>
user_path is a path helper in Rails which resolves to RESTful route of /users/:id. This goes in UserController#show and expects params hash to contain :id.
For your case, you are missing the argument. You need to do:
<button><%= link_to "Profile", user_path(current_user) %></button>
It automatically picks up id and passes it to params hash as : {:id => 7}
Doc
You may also want fix other such helpers call:
event_path
edit_event_path with appropriate argument.
What are you using for user authentication, devise or similar gem? Did you build your own? If so do you have current_user defined in the sessions helper? The below code is how current_user could be defined (a la Hartl Rails tutorial). This will allow you to use current_user in views and controllers.
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end
I also noticed in your Users Controller under def create. I believe it should be session[:id] instead of session[:uid]. Please excuse me if this is not the case. Hope this helps.
I set up posts in a folder called 'contents' and then it fell over when I tried to delete the records. Why am I getting this error?
No route matches {:action=>"edit", :controller=>"content/stories", :id=>nil} missing required keys: [:id]
Routes.rb
namespace :content do
resources :posts
end
PostsController
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = current_user.posts.new(post_params)
if #post.save
redirect_to content_posts_path
else
redirect_to root_path, notice: #post.errors.full_messages.first
end
end
def show
end
def delete
#post = Post.find(params[:id])
end
def destroy
post = Post.find(params[:id]).destroy
redirect_to :back
end
private
def post_params
params.require(:post).permit(:content)
end
end
show.html
<ol>
<% for p in #posts %>
<li>
<%= p.title %>
<%= link_to 'Edit', edit_content_post_path(#post) %>
<%= link_to 'Delete', content_post_path(#post), method: :delete %>
</li>
<% end %>
</ol>
#post is not defined, you probably need to use p in place of #post.
Also in your show.html which corresponds to show action, not sure how you are getting #posts.
I am trying to get my followers to display on the pages/friends however, I keep getting multiple errors like an undefined method `each' for nil:NilClass in my Pages#friends error. I am following Michael Harlts tutorials on follow/unfollow however, I needed to tweak a couple of things because I did not follow the entire thing.
When a user goes to their Friends link (pages/friends) I want it to display everyone who is following them. Like how my users/index displays everyone. Please see my code below. Any help of suggestions would be great.
Pages/friends
<h1>Friends</h1>
<% #user ||= current_user %>
<% #users.each do |user| %>
<center><%= link_to image_tag(user.avatar.url(:thumb)), user %></center>
<strong><center><br><%= link_to user.name, user %></br></center></strong>
<% if current_user.admin %>
<% end %>
<% end %>
Pages/controller
def home
end
def about
end
def friends
end
end
**Users/index*
<% provide(:title, 'All users') %>
<h1>All users</h1>
<div class="col-md-offset-4 col-med-8">
<div class="panel panel-default">
<div class="panel-heading center">
<% #users.each do |user| %>
<center><%= link_to image_tag(user.avatar.url(:thumb)), user %></center>
<strong><center><br><%= link_to user.name, user %></br></center></strong>
<% if current_user.admin %>
<% #user ||= current_user %>
<div class="stats">
<a href="<%= friends_path(#user) %>">
<strong id="following" class="stat">
<%= #user.followed_users.count %>
</strong>
following
</a>
<a href="<%= friends_path(#user) %>">
<strong id="followers" class="stat">
<%= #user.followers.count %>
</strong>
followers
</a>
</div>
<center><%= link_to "Delete", user, method: :delete, data: { confirm: "Are you sure?" } %></center>
<% end %>
<% end %>
<div class="center">
<%= will_paginate #users, renderer: BootstrapPagination::Rails %>
</div>
</div>
Routes
devise_for :admins
devise_for :users
resources :posts
resources :users do
member do
get :following, :followers
end
end
resources :relationships, only: [:create, :destroy]
resources :user_friendships do
member do
put :accept
end
end
get "users/show"
root "pages#home"
get 'feed', to: 'posts#index', as: :feed
get "about" => "pages#about"
get "friends" => 'pages#friends'
match 'users/:id' => 'users#show', via: :get
match 'users/:id' => 'users#index', via: :destroy
match 'users/:id' => 'users#destroy', via: :get
match 'users/:id' => 'users#destroy', via: :delete
get '/:id', to: 'users#show'
Users/controller
class UsersController < ApplicationController
before_action :correct_user, only: [:edit, :update, :destroy, :following, :followers]
before_action :authenticate_user!, except: [:index, :show]
before_action :admin_user, only: :destroy
def index
#users = User.paginate(page: params[:page], :per_page => 5)
end
def show
#user = User.find(params[:id])
if #user
#posts = #user.posts.all
render actions: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "Your account has been deleted."
redirect_to root_path
end
def correct_user
#user = User.find(params[:id])
redirect_to root_path
end
def admin_user
redirect_to root_path unless current_user.admin?
end
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.followed_users.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
end
end
Relationships Controller
class RelationshipsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
end
The error undefined method 'each' for nil:NilClass means that you're calling .each on an object that is nil.
For example, here, #users could be nil:
def index
#users = User.paginate(page: params[:page], :per_page => 5)
end
If you then call <% #users.each ... %>, you'll get the undefined method error. You've posted quite a lot of code above, so it's difficult to know exactly where that error is being thrown. Try and work out exactly where the error is being thrown (posting a stack trace would help), and work out which object is nil. Then work out why it's nil - is there no data? Or is your ActiveRecord query returning no results?
Hopefully that gives you some pointers as to where to start looking next.
Edit: As mmichael points out, the error is being caused due to the fact that #users was undeclared in pages#friends. Thanks!
As you're new, I'll give you another opinion. What I'm going to write is similar to Sam's answer; I intend to help you appreciate how Rails works, to further your experience
Objects
You must remember that Rails is built on top of Ruby - an object-orientated language. This means every time you declare / use a variable inside Ruby, you're actually accessing an object, which Ruby treats as having a series of methods:
Ruby is pure object-oriented language and everything appears to Ruby
as an object. Every value in Ruby is an object, even the most
primitive things: strings, numbers and even true and false. Even a
class itself is an object that is an instance of the Class class. This
chapter will take you through all the major functionalities related to
Object Oriented Ruby.
I write this because Ruby's object-orientated structure is much different than handling variables in the "traditional" sense -- in the simplest description, it means that Ruby presumes that objects are ALWAYS present (it just builds them from the NilClass), allowing you call "empty" data sets without running into "undeclared" issues
The problems occur when you try and run methods like .each on empty / nil objects. If you do this, errors like the one you alluded to occur; preventing you from being able to perform the functionality which you intended
--
Fix
Your error basically means you haven't declared your variable.
After seeing your code, the most obvious problem will be here:
#app/controllers/pages_controller.rb
Class PagesController < ApplicationController
def friends
# normally, you'd define your #instance_variables here
end
end
I see that your friends action does not declare your #users variable, which is required to perform the #users.each method. As recommended by Sam, the first step is to ensure you're able to declare this value, allowing you to loop through it as required:
#app/controllers/pages_controller.rb
Class PagesController < ApplicationController
def friends
#users = User.all
end
end