I'm getting a NoMethodError in Users#Index with an 'undefined method `each' for nil:NilClass' for the line below:
<% #users.each do |user| %>
I'm not sure where the problem resides. Any help is greatly appreciated. Thanks in advance. I know I am missing something extremely easy here.
User/Index
<div class="page-header">
<center><strong><h1> All Users </h1></strong></center>
</div>
<div class="row">
<% #users.each do |user| %>
<div class="horizontal-align col-md-2">
<div class="user">
<center><%= link_to image_tag(user.avatar.url(:thumb)), user %></center>
<center><br><%= link_to user.name, user %></br></center>
<% if current_user.admin %>
<center><%= link_to "Delete", user, method: :delete, data: { confirm: "Are you sure?" } %></center>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
<div class="center">
<%= will_paginate #users, renderer: BootstrapPagination::Rails %>
</div>
</div>
User/Show
<% provide(:title, #user.name) %>
<div class="row">
<aside class="span4">
<section>
<h1>
<%= image_tag #user.avatar.url(:thumb) %>
<%= #user.name %>
</h1>
<section>
<%= render 'users/stats' %>
</section>
<% if current_user.following?(#user) %>
<%= render 'users/unfollow' %>
<% else %>
<%= render 'users/follow' %>
<% end %>
User/Controller
class UsersController < ApplicationController
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
before_action :admin_user, only: :destroy
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
def index
#users = User.paginate(page: params[:page], :per_page => 20)
end
def show
#user = User.find(params[:id])
if #user
#posts = #user.posts.order("updated_at DESC")
render actions: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
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
end
The error NoMethodError means that you are calling a method that doesn't exist for the given class. In this case it is nil:NilClass which, obvious, doesn't contain the method each because it is nil! So let's examine:
You are calling #users.each which is calling the error. Since it says that the method if undefined for nil (as described above) it tells us that on the index page, #users is nil (probably not what it is intended to be!).
So it looks like the problem rests in your definition of #users. I'm not entirely sure, but it looks as though, in your UsersController that you have an extra end after the def following which would cause the controller to end prematurely, and therefore not define #users. (You can test that by changing it to #users = User.all which should work).
Let me know how things turn out
Related
I made Authentication in the rails blog project, but those who log in to the site, that is, admin can edit and destroy, guest user cannot edit destroy. I'm very new to rails and I don't know what to add. and how to make guest user login? guest user only read.
index.html
<div class="container">
<div class="row">
<% #articles.each do |article| %>
<div class="col-md-6">
<div class="row g-0 rounded overflow-hidden shadow-lg h-md-250">
<div class="col p-4 d-flex flex-column">
<strong class="mb-2 text-primary"><%= article.title %></strong>
<h3 class="mb-0"></h3>
<div class="mb-1 text-muted"><%= article.created_at.strftime("%d.%m.%Y %H:%M") %>
</div>
<p><%= article.text.truncate(110) %></p>
<div>
<%= link_to "Read more", article_path(article)%><br/><br/>
<tr>
<%= link_to 'Show', article_path(article),class:"btn btn-outline-success btn-sm"%>
<%= link_to 'Edit', edit_article_path(article),class:"btn btn-outline-warning btn-sm"%>
<%= link_to 'Destroy', article_path(article),class:"btn btn-outline-danger btn-sm",
method: :delete,
data: { confirm: 'Are you sure?' } %>
</tr>
</div>
</div>
</div>
</div>
<% end %>
</div>
<br/><br/>
<%= link_to 'New article', new_article_path,class:"btn btn-dark" %>
<%# sayfada show, edit, destroy butonları aktive oldu %>
</div>
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
end
articles_controller.rb
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def edit
#article = Article.find(params[:id])
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
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)
end
end
You haven't mentioned how you implemented authentication - I am assuming you added the gem Devise by looking at your code, but anyway you will have to somehow store each user's role. For example add an admin column to your User model
rails g migration AddsAdminColumnToUsers
def change
add_column :users, :admin, :boolean, default: false, null: false
end
and then force this requirement in your views and controller
<% if current_user.admin? %>
<%= link_to 'Edit', edit_article_path(article),class:"btn btn-outline-warning btn-sm"%>
<%= link_to 'Destroy', article_path(article),class:"btn btn-outline-danger btn-sm",
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
class ArticlesController < ApplicationController
def destroy
raise "unauthorized" unless current_user.admin?
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
def edit
raise "unauthorized" unless current_user.admin?
...
end
end
Many people use gems like Rolify and CanCan but for simple needs this approach can work without any gems.
Hello friends i have this error I've been facing yesterday on my Rails App. I get undefined method `articles' for nil:NilClass when i tried to display related articles on my article show page.
Here is my app codes
tag.rb
class Tag < ApplicationRecord
has_many :taggings
has_many :articles, through: :taggings
def to_s
name
end
end
tagging.rb
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :article
end
articles_controller
class ArticlesController < ApplicationController
before_action :find_article, only: [:show, :edit, :update, :destroy]
before_action :owned_article, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#articles = Article.all.order("created_at desc")
end
def show
end
def new
#article = current_user.articles.build
end
def create
#article = current_user.articles.build(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def edit
end
def update
if #article.update(article_params)
redirect_to #article, notice: "Your article was successfully updated!"
else
render 'edit'
end
end
def destroy
#article.destroy
redirect_to articles_path
end
private
def find_article
#article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:title, :content, :image, :tag_list)
end
def owned_article
unless current_user == #article.user
flash[:alert] = "That article does not belong to you!"
redirect_to root_path
end
end
end
articles show.html.erb
<div class="container">
<div class="row text-white text-center">
<div class="col-md-10 col-lg-10 ml-sm-auto mr-sm-auto article-show-col">
<br>
<h1><%= #article.title %></h1>
<p class="text-muted">Posted on: <%= #article.created_at.strftime('%-b %-d, %Y') %></p>
<p>
Tags:
<% #article.tags.each do |tag| %>
<%= link_to tag.name, tag_path(tag) %>
<% end %>
</p>
<!-- <br> -->
<div class="article-show-image">
<%= image_tag #article.image.url(:wide) %>
</div>
<!-- <br> -->
<p><%= #article.content.html_safe %></p>
<hr class="index-hr">
<h5>Broadcast this article</h5>
<%= social_share_button_tag("Hey! Checkout this new article from TWM!") %>
<hr class="index-hr">
**<h5>Related Articles</h5>
<% #tag.articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>**
<div class="btn-group">
<%= link_to "Back", articles_path, class: "btn-custom btn-sm" %>
<% if user_signed_in? %>
<% if #article.user_id == current_user.id %>
<%= link_to "Delete", article_path(#article), method: :delete, data: { confirm: "Are you sure you want to delete this article?" }, class: "btn-custom btn-sm" %>
<%= link_to "Edit", edit_article_path, class: "btn-custom btn-sm" %>
<% end %>
<% end %>
</div>
</div>
</div>
tags controller
class TagsController < ApplicationController
before_action :find_article, only: [:show, :edit, :update, :destroy]
def index
#tags = Tag.all.order("created_at desc")
end
def show
end
def destroy
#tag.destroy
redirect_to tags_path
end
private
def find_article
#tag = Tag.find(params[:id])
end
end
show view for tags
<div class="container text-white text-center">
<h1>Articles Tagged with <%= #tag.name %></h1>
<ul>
<% #tag.articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>
</ul>
Thank You!
Here is a longer answer that offers a solution to your problem. The issue is that you want to get all articles that share a tag with the article you are showing, while presumably not showing the current article in the list of related articles. I would accomplish this by adding a related_articles method to your Article model and calling it in your view.
Add the following method to app/models/article.rb:
def related_articles
Article.joins(:tags).where(tags: { id: self.tags.pluck(:id) }).where.not(id: self.id)
end
The above query should return all of the articles that have a matching tag while excluding itself.
You can now replace the related articles section in your view with:
**<h5>Related Articles</h5>
<% #article.related_articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>**
One final note that is not strictly related to your problem, but worth mentioning. By iterating over #article.tags, your view is creating an N+1 query. These are very inefficient. The good news, is that this can be fixed with eager loading by simply, changing the find_articles method in your articles_controller as follows:
def find_article
#article = Article.includes(:tags).find(params[:id])
end
There may be a more efficient way to write the related_articles query, but this should work.
EDIT:
Another way of writing the related_articles query follows. This will yield the same results. It moves more of the processing to the database and results in fewer calls to the database.
def related_articles
Article.distinct.joins(tags: :articles).where.not(id: self.id)
end
Your ArticlesController is not instantiating #tag variable while it is used in the show view.
In your show.html.erb, you're trying to do:
<div class="container">
<div class="row text-white text-center">
<div class="col-md-10 col-lg-10 ml-sm-auto mr-sm-auto article-show-col">
...
<% #tag.articles.each do |article| %>
<li><%= link_to article.title, article_path(article) %></li>
<% end %>**
...
</div>
</div>
</div>
But, hey, check it out! No #tag in your show action:
class ArticlesController < ApplicationController
before_action :find_article, only: [:show, :edit, :update, :destroy]
before_action :owned_article, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
...
def show
#look! no #tag
end
...
end
I am creating a "to-do website". Users can log in and generate tasks as well as notes. The tasks work perfectly but I have some issues with notes for some reason. I don't use any partials for notes. If I use this on my index.html.erb as I did for the tasks:
<div class="notes">
<%= link_to 'New Note', new_note_path %>
<div class="note">
<div>
<%= link_to note_path(note) do %>
<%= note.content %>
<%= link_to 'X', note, :class => 'task-destroy', method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
</div>
<div>
<%= link_to edit_note_path(note) do %>
<%= time_ago_in_words(note.updated_at) %> ago
<% end %>
</div>
</div>
</div>
I get:
"NameError in NotesController#index" - "undefined local variable or
method `note' for #..."
notes_controller.rb
class NotesController < ApplicationController
before_action :logged_in_user
before_action :set_note, only: [:show, :edit, :update, :destroy]
def index
#notes = current_user.notes
end
def show
end
def new
#note = Note.new
end
def edit
end
def create
#note = current_user.notes.new(note_params)
if #note.save
flash[:success] = "You successfully created a Note!"
redirect_to notes_path
else
render 'new_note_path'
end
end
def update
#note.update(note_params)
if #note.save
flash[:success] = "You successfully updated a Note!"
redirect_to notes_path
else
render 'edit_note_path'
end
end
def destroy
#note.destroy
flash[:success] = "You successfully deleted a Note!"
redirect_to notes_path
end
private
def set_note
#note = Note.find(params[:id])
end
def note_params
params.require(:note).permit(:content)
end
end
Question: What is wrong with my instance variable on my controller and how can I make it work?
add loop before <div class="note"> to loop through list of notes stored in #notes in your index action.
Html should look like this:
<% #notes.each do |note| %>
<div class="note">
<div>
<%= link_to note_path(note) do %>
<%= note.content %>
<%= link_to 'X', note, :class => 'task-destroy', method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
</div>
<div>
<%= link_to edit_note_path(note) do %>
<%= time_ago_in_words(note.updated_at) %> ago
<% end %>
</div>
</div>
</div>
<% end %>
Your index.html.erb view doesn't have access to a note variable.
The instance variable from the following method is the only variable being passed to the view:
def index
#notes = current_user.notes
end
You would probably need to do something like,
<% #notes.each do |n| >
<%= link_to(n) >
<% end >
I've been following the Michael Hartl guide and the only error that I see (but the system doesn't catch), is that every time there is a flash like in the image below, the alert shows up twice as opposed to once. I've spent way too long troubleshooting this. Where would I edit the flash behavior.
http://imgur.com/Lws5z4o
Here is my User Controller
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
#users = User.paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params) # Not the final implementation!
if #user.save
UserMailer.account_activation(#user).deliver_now
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile Updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
#Before filters
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.admin?
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
My Application Layout
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<% flash.each do |message_type, message| %>
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>
Change...
<% flash.each do |message_type, message| %>
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
to...
<% flash.each do |message_type, message| %>
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
<% end %>
The flash behavior isn't the issue. You're rendering error messages twice because you're duplicating the error message div in your flash.each do ... block.
Yes, it's very clear, look at your loop:
<% flash.each do |message_type, message| %>
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
You're outputting two divs per loop (ie. per flash message), one using the content_tag helper, and one using the <div literal text. Remove one of them.
I can't seem to implement this option: On my app, users can create posts and comment on posts as well. If a user wants to show a URL in either the www format or http format, how should I display that using the rails_autolink gem? I want the url to be clickable and take you to the link. I have already installed the gem and I added it to my posts controller. Another user suggested that gem to me but I do not understand how to implement it. Users create comments from the posts show template. Does the gem need to be used in the show template or the posts_controller?
this is my post show.html.erb:
<div class="page-header">
<h2>
<%= #post.title %>
<small>
posted by <%= link_to #post.creator.username %> <%= time_ago_in_words(#post.created_at) + ' ago' %>
| <%= link_to 'go to link', fix_url(#post.url) %>
<% if logged_in? && (#post.creator == current_user) %> |
<%= link_to 'edit', edit_post_path(#post) %> |
<i class="icon-user icon"></i>
<% end %>
</small>
</h2>
</div>
<h3><%= #post.description %></h3>
<%= render 'shared_partials/errors', errors_obj: #comment %>
<%= form_for [#post, #comment] do |f| %>
<%= f.text_area :body, :class=> "span4", :placeholder=> "Comment goes here", :rows => "7" %>
</br>
<div class="button">
<%= f.submit "Create a comment", class: 'btn btn-primary' %>
</div>
<% end %>
<div class="page-header">
<h4>All Comments</h4>
</div>
<% #post.newest_comments.each do |comment| %>
<div class="comments">
<h5><%= comment.body %></h5>
<li>
<small class="muted">
posted by <%= link_to comment.creator.username %> <%= time_ago_in_words(comment.created_at) + ' ago' %>
<% if logged_in? && (comment.creator == current_user) %> |
<%= link_to 'edit', edit_post_comment_path(#post, comment) %> |
<i class="icon-user icon"></i>
<% end %>
</small>
</li>
</div>
<% end %>
and my posts_controller:
require 'rails_autolink'
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :vote]
before_action :require_user, only: [:new, :create, :edit, :update, :vote]
before_action :require_creator, only:[:edit, :update]
def index
#posts = Post.page(params[:page]).order('created_at DESC').per_page(15)
end
def show
#comment = Comment.new
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.creator = current_user
if #post.save
flash[:notice] = "You created a post!"
redirect_to posts_path
else
render :new
end
end
def edit
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
flash[:notice] = "You updated the post!"
redirect_to post_path(#post)
else
render :edit
end
end
def vote
Vote.create(voteable: #post, creator: current_user, vote: params[:vote])
respond_to do |format|
format.js { render :vote } # Renders views/posts/vote.js.erb
end
end
private
def post_params
params.require(:post).permit(:url, :title, :description)
end
def set_post
#post = Post.find(params[:id])
end
def require_creator
access_denied if #post.creator != current_user
end
end
I'm not entirely sure that rails_autolink will do what you're looking to accomplish. Basically, per the documentation, the gem interpolates URLs in outputted text to a hyperlink that encloses the URL as text. By default, markup is outputted as sanitized html_safe strings:
auto_link("Go to http://www.rubyonrails.org and say hello")
# => "Go to http://www.rubyonrails.org and say hello"
You should be using it directly in your view/template and you should not need to require it in our controller. Rails typically requires gem dependencies at application load, so you don't need to include them at runtime.