Why my form won't submit correctly? - ruby-on-rails

I have User model and Comment model using acts_as_commentable_with_threading
I'm trying to put the comment function on each User's show page with partial.
But When I try to submit a form, it shows routing error.
Why is this?
Error
Routing Error
No route matches [POST] "/user/john/add_comment"
models/user.rb
acts_as_commentable
views/users/show.html.erb
<%= render 'comment', :user => #user %>
views/users/_comment.html.erb
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th>Subject</th>
<th>Posted by</th>
<th>Delete</th>
</tr>
<% #user.comment_threads.each do |comment| %>
<tr>
<td><%= comment.id %></td>
<td><%= comment.title %></td>
<td><%= comment.body %></td>
<td><%= comment.subject %></td>
<td><%= comment.user.user_profile.nickname if comment.user.user_profile %></td>
<td><%= button_to 'destroy', comment, confirm: 'Are you sure?', :disable_with => 'deleting...', method: :delete %></td>
</tr>
<% end %>
</table>
<%= form_for #user, :html => { :class => 'form-horizontal' } do |f| %>
<div class="field">
<%= f.label :body %><br />
<%= f.text_field :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
routes.rb
get "user/:id/add_comment" => 'users#add_comment', :as => :add_comment_user
get "user/:id/delete_comment" => 'users#delete_comment', :as => :delete_comment_user
users_controller.rb
def add_comment
#user = User.find_by_username(params[:id])
#user_who_commented = current_user
#comment = Comment.build_from( #user, #user_who_commented.id, params[:users][:body] )
#comment.save
redirect_to :controller => 'users', :action => 'show', :id => params[:users][:id]
flash[:notice] = "comment added!"
end

Because your route is for a GET, and the form is a POST.

It needs to be a post route. Also you are posting to user/:name/add_comment, you should post the the user id. You can use the name but this would need to be unique across all users.
This line is also wrong.
#user = User.find_by_username(params[:id])
You can either pass in the params[:username] of find_by_id

Related

Cancancan gem usage in rails application

I have a rails application which manages all the registered users. All crud operations can be done on the details of the registered users. I now need to restrict the application in such a way that only the admin user should be allowed to view all the registered users. Any user without the admin privilege should be able to view, edit, and delete his/her post only. I have used devise gem for authentication and plans to use cancancan gem for authorization. I have only a single model class called Users which contains a text attribute (to store "Admin" or "Nonadmin"). Here is my controller code:
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
if current_user.role == "Admin"
#users = User.all
else
#user = User.find(current_user.id)
end
redirect_to new_user_registration_path if current_user.nil?
respond_to do |format|
format.html
end
end
def show
if (User.all.pluck(:id).include?params[:id].to_i) == false
flash[:notice] = "You cannot perform such an action"
else
#user = User.find(params[:id])
end
respond_to do |format|
format.html
end
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to :action => 'index'
else
render :action => 'new'
end
end
def user_params
params.require(:user).permit(:first_name, :last_name, :age, :biography, :email)
end
def edit
if (User.all.pluck(:id).include?params[:id].to_i) == false
flash[:notice] = "You cannot perform such an action"
else
#user = User.find(params[:id])
end
respond_to do |format|
format.html
end
end
def update
params.inspect
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to :action => 'show', :id => #user
else
render :action => 'edit'
end
end
def delete
User.find(params[:id]).destroy
redirect_to :action => 'index'
end
end
My user table has the following fields: id,email,first_name,last_name,biography,email,role. It also contains all the devise-related fields.Below is my User model :
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
after_initialize :default_values
private
def default_values
self.role ||= "Non-admin"
end
end
I have hardcoded my admin credentials in seeds.rb as shown below:
if User.find_by(:role => 'Admin').nil?
User.create([{email:"admin_user#usermanagementsystem.com",password: "topsecret",first_name:"admin",last_name:"ums", biography: "i serve as admin at the ums", age:20, role: "Admin"}])
end
View files:
Index.html.erb:-
<table id="albums" cellspacing="0">
<thead>
<tr>
<th> NAME </th>
<th> EMAIL </th>
<% if current_user.role == "Admin" %>
<th> EDIT </th>
<th> SHOW </th>
<th> DESTROY </th>
<% end %>
<th colspan="15"></th>
</tr>
</thead>
<% if current_user.role == "Admin" %>
<% #users.each do |user| %>
<tr>
<td><%= user.first_name %></td>
<td><%= user.email %></td>
<td><%= link_to 'Edit', users_edit_path(id: user.id), class: "small button"%></td>
<td><%= link_to 'Show', users_show_path(id: user.id), class: "small button"%></td>
<td><%= link_to 'Destroy', users_delete_path(id: user.id), method: :delete, data: { confirm: 'Are you sure?' } , class: "small button"%></td>
</tr>
<% end %>
<% else %>
<tr>
<td><%= #user.first_name %></td>
<td><%= #user.email %></td>
<td><%= link_to 'Edit', users_edit_path(id: #user.id), class: "small button" %></td>
<td><%= link_to 'Destroy', users_delete_path(id: #user.id), method: :delete, data: { confirm: 'Are you sure?' } , class: "small button"%></td>
</tr>
<%end %>
</table>
<%#= link_to 'Change password', edit_user_registration_path, class: "small button" %>
edit.html.erb:-
<% if #user.nil? == false %>
<%= form_for #user , :as => :user, :url => users_update_path(#user), :method => :PUT do |f| %>
<%= f.label :first_name %>:
<%= f.text_field :first_name %><br>
<%= f.label :last_name %>:
<%= f.text_field :last_name %><br>
<%= f.label :age %>:
<%= f.number_field :age %><br>
<%= f.label :biography %>:
<%= f.text_field :biography %><br>
<%= f.label :email %>:
<%= f.text_field :email %><br>
<%= f.submit :class => 'small button' %>
<% end %>
<%else%>
<h3> Such a user record does not exist. Please click on a specific user </p>
<%end%>
show.html.erb
<br>
<br>
<% if #user.nil? == false %>
<h3>User details</h3>
<table id="albums" cellspacing="0">
<thead>
<tr>
<th>FIRSTNAME</th>
<th>LASTNAME</th>
<th>EMAIL</th>
<th>BIOGRAPHY</th>
<th>AGE</th>
<th colspan="20"></th>
</tr>
</thead>
<tr>
<td> <%= #user.first_name %> </td>
<td> <%= #user.last_name %> </td>
<td> <%= #user.email %> </td>
<td> <%= #user.biography %> </td>
<td> <%= #user.age %> </td>
</tr>
</table>
<%= link_to ' Edit ', users_edit_path(id: #user.id) , class: "small button"%>
<%= link_to 'Delete ', users_delete_path(id: #user.id), method: :delete, data: { confirm: 'Are you sure?' }, class: "small button" %>
<%else%>
<h3> Such a user record does not exist. Please click on a specific user </p>
<%= link_to "Logout", destroy_user_session_path, method: :delete, class: "small button" %>
</footer>
<%end%>
Can anyone help me out in using cancancan gem to restrict any user other than admin from viewing, editing, updating and deleting his own posts. Admin should be able to do these operations on everyone's records.
Please help me improve if you find me doing something wrong with the controller code too. Thanks in advance.
Added the following code to the initialize function of ability.rb and got it working correctly.
if user.role == "Admin"
can :manage, :all
else
can [:index], User, id: user.id
can [:show],User, id: user.id
can [:edit],User, id: user.id
can [:update], User,id: user.id
can [:delete],User, id: user.id
end

form_for submit button does not work for ruby on rails

my form_for submit button only works partially; the data is saved in the database but the redirection fails. Here are the relevant codes for the form:
app/views/orders/new.html.erb
<h1>Menu</h1>
<%= link_to "Back to channel", current_channel_path %>
<div class="container">
<table class="table table-striped">
<thead>
<tr>
<th>Meal</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<% #menu_items.each do |t| %>
<p>
<tr>
<td><%= t.name %></td>
<td><%= number_to_currency(t.price) %></td>
<%= form_for (#order), url: orders_path, remote: true do |f| %>
<td><%= f.number_field :quantity, value: 1, class: "form-control", min: 1 %></td>
<%= f.hidden_field :meal, :value => t.name %>
<%= f.hidden_field :unit_price, :value => t.price %>
<td><%= f.submit "Order", class: "btn btn-primary" %></td>
<% end %>
</tr>
</p>
<% end %>
</tbody>
</div>
Here are the codes for routes.rb
Rails.application.routes.draw do
#For Orders
get 'orders' => 'orders#new'
post 'orders' => 'orders#create'
get 'all_orders' => 'orders#show'
resources :users
resources :orders
Here are the relevant codes for orders
def new
#menu_items = MenuItem.all
#order = Order.new
end
def create
#order = current_channel.orders.build(order_params)
#order.user = current_user
if #order.save
flash.now[:success] = "Order has been recorded!"
redirect_to all_orders_path
else
flash.now[:danger] = "Order was not recorded!"
render 'new'
end
end
I read that the submit button may not work as it is nested in the table. I have tried putting the form outside of the table but the submit still does not redirect; the submit button however creates the record in the orders database in both cases. Any idea why this is the case? Thanks in advance for any help!
You need a route set for the index path which isn't listed above. If you're following standard crud conventions you should just use "resources :orders" in your routes files which will generate the post/put/delete/get routing you need. Then your redirection will work.

How to setup the actions with considering database design of rails3

Assume you have the model called 'Topic' as a parent, and 'Comment' as a child.
On the url 'topics/show/35' you can see all the comments that belongs to this topic ID#35.
When logged-in user want to post his new comment at this page,
should I write 'comment_create' action in topics_controller.rb?
or just write 'create' action in comments_controller.rb, and call it from this page?
Which one is regular way??
If I call 'create' action in comments_controller, how can I write in view to pass
'Model name' to add comments into
'Models ID#'
'comment body'
or should I just write actions separately like this?
controllers/comments_controller.rb
def create_in_topic
code here! to add new comment record that belongs to topic....
end
def create_in_user
code here! to add new comment record that belongs to user....
end
for your information, comment adding action should be something like this.
def create
#topic = Topic.find(params[:topics][:id] )
#user_who_commented = current_user
#comment = Comment.build_from( #topic, #user_who_commented.id, params[:topics][:body] )
#comment.save
redirect_to :back
flash[:notice] = "comment added!"
end
Example Updated!!!
views/topics/show.html.erb
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th>Subject</th>
<th>Posted by</th>
<th>Delete</th>
</tr>
<% #topic.comment_threads.each do |comment| %>
<tr>
<td><%= comment.id %></td>
<td><%= comment.title %></td>
<td><%= comment.body %></td>
<td><%= comment.subject %></td>
<td><%= comment.user.user_profile.nickname if comment.user.user_profile %></td>
<td> **Comment destroy method needed here!!!** </td>
</tr>
<% end %>
</table>
<%=form_for :topics, url: url_for( :controller => :topics, :action => :add_comment ) do |f| %>
<div class="field">
<%= f.label :'comment' %><br />
<%= f.text_field :body %>
</div>
<%= f.hidden_field :id, :value => #topic.id %>
<div class="actions">
<%= f.submit %>
<% end %>
controllers/topics_controller.rb
def add_comment
#topic = Topic.find(params[:topics][:id] )
#user_who_commented = current_user
#comment = Comment.build_from( #topic, #user_who_commented.id, params[:topics][:body] )
#comment.save
redirect_to :back
flash[:notice] = "comment added!"
end
I think the most straight forward implementation it's going to be an action (ie: add_comment) in your Topic Controller. Once the view call the TopicController#add_comment action you will have all your Topic information and also the comment data so you can easily add the comment to the Topic from there.
Let me know if you need further help.
FedeX
Well I'm not to sure because that gem, but you could try something like this:
<%=form_for #topic, url: url_for( :controller => :topics, :action => :add_comment ) do |f| %>
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th>Subject</th>
<th>Posted by</th>
<th>Delete</th>
</tr>
<% #topic.comment_threads.each do |comment| %>
<%= f.fields_for :comment_threads, comment do |comment_form| %>
<tr>
<td><%= comment.id %></td>
<td><%= comment.title %></td>
<td><%= comment.body %></td>
<td><%= comment.subject %></td>
<td><%= comment.user.user_profile.nickname if comment.user.user_profile %></td>
<td>Delete? <%= comment_form.check_box :_destroy %></td>
</tr>
<% end %>
<% end %>
</table>
<div class="field">
<%= f.label :'comment' %><br />
<%= f.text_field :body %>
</div>
<%= f.hidden_field :id, :value => #topic.id %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Let me know if it helps you! FedeX

authlogic and posts for current_user

I am using authlogic for users to login and once they do so, I would like them to be able to add posts. For some reason I keep getting "Couldn't find User without an ID". Below is my code:
posts controller
def create
#user = User.find(params[:user_id])
#post = #user.posts.create(params[:post])
redirect_to current_user_path(#current_user)
end
show page
<% #user.posts.each do |post| %>
<tr>
<td><%= post.postName %></td>
<td><%= post.body %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %> </td>
</tr>
<% end %>
</table>
<br />
<h2>Add a Post:</h2>
<%= form_for([#current_user, #user.posts.build]) do |f| %>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I know it has something to do with current user, but I cannot get this working! Any help is greatly appreciated!
First, you should use current_user not #current_user
Second, you're doing #user = User.find(params[:user_id]) but I don't understand why you expect to have something like :user_id in your params. That's why you get that "Couldn't find User without an ID" error.

Rails 3 AJAX problem - UJS

Ok so here is my setup, I think I have everything set up correctly but for some reason the page isn't displaying the AJAX response.
Basically I have a members list and want to display their "profile" with ajax on the same page.
In views/member/index.html.erb
<table>
<tr>
<th>Name</th>
</tr>
<% #members.each do |member| %>
<tr>
<td><%= member.name %> & <%= member.sname %></td>
<td><%= link_to 'Show', member, :remote => true %></td>
<td><%= link_to 'Edit', edit_member_path(member) %></td>
<td><%= link_to 'Destroy', member, :confirm => 'Are you sure?', :method => :delete %> </td>
</tr>
<% end %>
</table>
<%= link_to 'New Member', new_member_path %>
<div id="memberprofile">
</div>
In my members controller I have this:
def show
#member = Member.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.js
format.xml { render :xml => #member }
end
end
Then in my _show.js.rjs I have this
page.replace_html('memberprofile', render(#member))
Then in my _member.html.erb partial I have this:
<h1><%= #member.name %></h1>
A few questions:
1) From the console it says "Rendered members/show.html.erb" but I thought it would just render the member partial. why is this?
2) Nothing is happening in the index.html.erb page when the ajax call goes out. I thought having the div hook plus the javascript file would do the trick...
Thanks guys
you have to create a new partial that only display the profile of member. Lets say the partial name is _member.html.erb
in your index file do:
<%= javascript_include_tag "jquery-1.4.4.min.js", "jquery.form" %>
<script type="text/javascript"> var $j = jQuery.noConflict();</script>
<table>
<tr>
<th>Name</th>
</tr>
<% #members.each do |member| %>
<tr>
<td><%= member.name %> & <%= member.sname %></td>
<td><%= link_to 'Show', "javascript:", :onclick => "show_member(member.id)" %></td>
<td><%= link_to 'Edit', edit_member_path(member) %></td>
<td><%= link_to 'Destroy', member, :confirm => 'Are you sure?', :method => :delete %> </td>
</tr>
<% end %>
</table>
<%= link_to 'New Member', new_member_path %>
<div id="memberprofile">
</div>
<script type="text/javascript">
function show_member(m_id) {
var container = $j("#memberprofile");
$j.ajax({
url: '/members/get_member?mid=' + m_id, type: 'get', dataType: 'html',
processData: false,
success: function(data) {
container.html(data);
}
});
}
</script>
in your routes do something like:
resources :members do
collection do
get :get_member
end
end
in your controller do:
def get_member
#member = Member.find_by_id(params[:mid])
render :partial => "member", :layout => false, :locals => {:member => #member}
end
in your _member.html.erb partial
<% unless #member.blank? %>
<h1><%= #member.name %></h1>
<% else %>
Record not found :(
<% end %>

Resources