How to combine a <div> with a Rails "link_to"? - ruby-on-rails

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 >

Related

hide "edit" and "destroy" unless logged in as admin

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.

Rails create action Ajax returns Template Missing or Unknown Fomat

I'm trying to implement private_pub on a one-to-one chat app, without private_pub everything works fine just not ideal chat app since no websocket is used for autoupdates.
I tried implementing as on RailsCasts of private_pub but i am getting either template missing or unknown format.
Here is my code:
Routes
resources :conversations do
resources :messages
end
I have a button in my user show page to start a chat(which creates/uses a conversation and shows up a conversation show page like a one to one chat box on facebook/gchat , a conversation has many messages):
<% unless current_user == #user %>
<%= link_to "Send Message", conversations_path(:sender_id => current_user.id , :recipient_id => #user.id ), :method => :post, class: "btn btn-success btn-xs start-conversation" %>
<% end %>
Conversation Controller
class ConversationsController < ApplicationController
before_filter :authenticate_user!
layout false
def create
if Conversation.between(params[:sender_id],params[:recipient_id]).present?
#conversation = Conversation.between(params[:sender_id],params[:recipient_id]).first
else
#conversation = Conversation.create!(conversation_params)
end
#conversation.save!
redirect_to #conversation
end
def show
#conversation = Conversation.find(params[:id])
#reciever = interlocutor(#conversation)
#messages = #conversation.messages
#message = Message.new
end
private
def conversation_params
params.permit(:sender_id, :recipient_id)
end
def interlocutor(conversation)
current_user == conversation.recipient ? conversation.sender : conversation.recipient
end
end
Convesation Show View
<% content_for :bottom do %>
<%= subscribe_to conversation_path(#conversation) %>
<% end %>
<div class="chatboxhead">
<div class="chatboxtitle">
<i class="fa fa-comments"></i>
<h1><%= #reciever.username %> </h1>
</div>
<div class="chatboxoptions">
<%= link_to "<i class='fa fa-minus'></i> ".html_safe, "#", class: "toggleChatBox", "data-cid" => #conversation.id %>
<%= link_to "<i class='fa fa-times'></i> ".html_safe, "#", class: "closeChat", "data-cid" => #conversation.id %>
</div>
<br clear="all"/>
</div>
<div class="chatboxcontent">
<% if #messages.any? %>
<%= render #messages.reverse %>
<% end %>
</div>
<div class="chatboxinput">
<%= form_for([#conversation, #message], :remote => true) do |f| %>
<%= f.text_area :body, class: "chatboxtextarea", "data-cid" => #conversation.id %>
<%= f.submit " Send", class: "btn btn-primary btn-xs"%>
<% end %>
</div>
Message Controller
class MessagesController < ApplicationController
before_filter :authenticate_user!
skip_before_filter :verify_authenticity_token, only: [:create]
def create
#conversation = Conversation.find(params[:conversation_id])
#message = #conversation.messages.build(message_params)
#message.user_id = current_user.id
#message.save!
#path = conversation_path(#conversation)
end
private
def message_params
params.require(:message).permit(:body)
end
end
Message's message partial
#_message.html.erb
<li class="<%= self_or_other(message) %>">
<div class="avatar">
<img src="http://placehold.it/50x50" />
</div>
<div class="chatboxmessagecontent">
<p><%= message.body %></p>
<time datetime="<%= message.created_at %>" title="<%= message.created_at.strftime("%d %b %Y at %I:%M%p") %>">
<%= message_interlocutor(message).username %> <%= message.created_at.strftime("%H:%M %p") %>
</time>
</div>
</li>
Message's create view
#create.js.erb
<% publish_to #path do %>
var id = "<%= #conversation.id %>";
var chatbox = $(".chatboxcontent");
var sender_id = "<%= #message.user.id %>";
var reciever_id = $('meta[name=user-id]').attr("content");
chatbox.append("<%= j render( partial: #message ) %>");
chatbox.scrollTop(chatbox[0].scrollHeight);
if (sender_id != reciever_id) {
chatBox.chatWith(id);
chatbox.children().last().removeClass("self").addClass("other");
chatbox.scrollTop(chatbox[0].scrollHeight);
chatBox.notify();
}
<% end %>
On Message Controller, create action the above code results "Missing Template" and if I put a respond_to as:
respond_to do |format|
format.js { render 'create.js.erb' }
end
it results "Unknown Format"
This error occurs when you have not added jquery_ujs file. You only included the jquery file.
So you need to add both files manually in you view or require them in application.js or any other file which you are using for specific layout.
Depending upon your scenario, you can follow 1st or 2nd solution.
1st solution:
<%= javascript_include_tag :jquery, :jquery_ujs %>
on your conversation show page.
2nd solution:
remove the "layout false" on your conversation controller

Rails how to send params[:commit] value

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" %>

flash[:notice] not working in Rails 4 after edit/create action

I can get flash messaging to work after create and destroy when they are redirected to root_path but cannot get it to work when update redirects to show.html.erb for some reason. What do you think is the problem? My Quote model has 4 columns(id, category, author and quotetext)
My show view
<% if !flash[:notice].blank? %>
<div class="notice">
<%= flash[:notice] %>
</div>
<% end %>
<% #category.each do |quote| %>
<div>
<p><strong> <%= quote.category %></strong></p>
<p><em><%= quote.author %></em></p>
<p> <%= quote.text %> </p>
<hr>
</div>
<% end %>
<%= link_to 'Home', quotes_path %>
My controller:
class QuotesController < ApplicationController
before_action :set_quote, only: [:show, :edit, :update, :destroy]
# GET /quotes
# GET /quotes.json
def index
#quotes = Quote.sorted
end
# GET /quotes/1
# GET /quotes/1.json
def show
#quote = Quote.find(params[:id])
end
# GET /quotes/new
def new
#quote = Quote.new
#apparently this doesn't really do anything but good to specify
end
def create
#quote = Quote.new(quote_params)
if #quote.save
flash[:notice] = "Quote #{#quote.pkey} created!"
redirect_to root_path
else
render('new')
end
end
# GET /quotes/1/edit
def edit
#quote = Quote.find(params[:id])
end
# PATCH/PUT /quotes/1
# PATCH/PUT /quotes/1.json
def update
#quote = Quote.find(params[:id])
if #quote.update_attributes(quote_params)
flash[:notice] = "Quote #{#quote.pkey} updated!"
redirect_to(:action => 'show', :id => #quote.id)
else
render('edit')
end
end
# DELETE /quotes/1
# DELETE /quotes/1.json
def destroy
#quote = Quote.find(params[:id]).destroy
flash[:notice] = "Quote #{#quote.pkey} deleted!"
redirect_to root_path
end
private
def set_quote
#quote = Quote.find(params[:id])
end
def quote_params
params.require(:quote).permit(:category, :author, :quotetext)
end
end
my index view
<div class='jumbotron'>
<h1>Root Index Page</h1>
</div>
<%= render 'shared/nav' %>
<div class="quotes index">
<%= render 'flash' %>
<table class="listing">
<tr class="header">
<th>Pkey</th>
<th>Category</th>
<th>Author</th>
<th>Quote Text </th>
</tr>
<% #quotes.each do |quote| %>
<tr>
<td><%=quote.pkey %></td>
<td><%=quote.category %></td>
<td><%=quote.author %></td>
<td><%=quote.text %></td>
<td class="actions">
<%= link_to("Show", {:action => 'show', :id => quote.id}) %>
<%= link_to("Edit", {:action => 'edit', :id => quote.id}) %>
<%= link_to quote_path(quote.id), method: :delete, data: {confirm: "Really delete Quote ##{quote.id}?"} do %><span class=edit>Delete</span><% end %>
</td>
</tr>
<% end %>
</table>
</div>
my edit view
<h1>Edit Existing Quote <%=#quote.pkey%> </h1>
<%= form_for(#quote) do |f| %>
<p>
<%= f.label :category %><br>
<%= f.text_field :category %>
</p>
<p>
<%= f.label :author %><br>
<%= f.text_field :author %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :quotetext %>
</p>
<div class="actions">
<%= f.submit "Update quote" %>
</div>
<% end %>
<%= link_to 'Show', #quote %> |
<%= link_to 'Back', quotes_path %>
flash partial
<% if !flash[:notice].blank? %>
<div class="notice">
<%= flash[:notice] %>
</div>
<% end %>
flash.keep is a method applied to flash an the params should be passed as argument, not array:
flash.keep(:notice)
http://guides.rubyonrails.org/action_controller_overview.html#the-flash
And the source code:
http://api.rubyonrails.org/classes/ActionDispatch/Flash/FlashHash.html#method-i-keep

rails_autolink gem for my comments issues

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.

Resources