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.
Related
I am having problem in my rails controller that my index, show pages won't be appearing in my server, this is my code in controller:
class GamesController < ApplicationController
def index
#games=Game.all
#render_carousel = true
end
def new
#game=Game.new
end
def create
#game=Game.new(game_params)
if #game.save
flash[:notice] = 'game created'
redirect_to games_path
else
render 'new'
end
end
def edit
#game=Game.find(params[:id])
end
def update
#game=Game.find(params[:id])
if #game.update(game_params)
flash[:notice] = 'game updated'
redirect_to games_path
else
render 'edit'
end
end
def destroy
#game=Game.find(params[:id])
#game.destroy(game_params)
flash[:notice] = 'game deleted'
redirect_to games_path
end
def show
#game=Game.find(params[:id])
end
private
def game_params
params.require(:game).permit(:name, :year, :description, :price, :category_id, :creator_id,:coverpath)
end
end
This is my index page code: I get the error in link_to line, and the error is in index and show page
<div id="page-index">
<div class="row">
<div class="col-md-3 col-sm-3">
<div class="thumbnail">
<%= image_tag('cover/un1.jpg')%>
<h4><b>Uncharted</b></h4>
<p>The Uncharted series is one of the best action adventure franchises in recent gaming history,
</p>
<%= link_to 'Read More' ,#game_path(game), class:'btn btn-primary'%>
<div>
</div>
</div>
</div>
Do this:
<%= link_to 'Read More', game_path(game), class:'btn btn-primary'%>
or, just this:
<%= link_to 'Read More', game, class: 'btn btn-primary'%>
Both should work as long as game is actually present in the database.
Update
Loop through the #games and show the each game link in your index.html.erb file:
<% #games.each do |game| %>
<%= link_to 'Read More', game_path(game), class:'btn btn-primary'%>
<% end %>
I am building a blog application in which I am trying to send some values like
post.id
params[:commit] (value )
So from my show action I am sending these 2 values to my edit action in my posts controller but i am unable to collect params[:commit] value ..in my case for approve it will send 'approve' and for decline it will send 'decline' but it is not sending
[posts/show.html.erb]
<div id="post_content">
<h1 class="title"><%= #post.title %></h1>
<p class="date">
Submitted <%= time_ago_in_words(#post.created_at) %> Ago
<% if user_signed_in? %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Delete', post_path(#post), method: :delete, data: { confirm: 'Are you sure?' } %>
<%= link_to "approve",[:edit,#post] ,commit: "Approve"%>
<%= link_to "decline",[:edit,#post],commit: "decline" %>
<% end %>
</p>
<p class="body"><%= #post.body %></p>
<div id="comments">
<h2><%= #post.comments.count %> Comments</h2>
<%= render #post.comments %>
<h3>Add a comment:</h3>
<%= render "comments/form" %>
</div>
</div>
[posts_controller.rb]
class PostsController < ApplicationController
before_action :authenticate_user!
def index
#posts = Post.user_post(current_user).order('created_at DESC').paginate(:page => params[:page], :per_page => 5)
end
def new
#post = Post.new
end
def show
#post=find_params
end
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save
Post.upload(params[:post][:files],#post.id)
redirect_to #post
else
render 'new'
end
end
def edit
#post = find_params
puts "cccccccccc#{params[:commit]}"
Post.up(#post.id,params[:commit])
end
def update
#post = find_params
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = find_params
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :body)
end
def find_params
Post.find(params[:id])
end
end
Change your link_to tag according to this.
<%= link_to "approve", edit_post_path(#post, commit: "Approve") %>
<%= link_to "decline", edit_post_path(#post, commit: "Decline" %>
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'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
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.