I just wanted to know if there is any method available to update a record of a table from a view? For example am I able to delete a record from the table using the code below?
<td><%= link_to 'Delete', my_path(user), :confirm => 'Are you sure?', :method =>:delete, :remote=>true %></td>
And in my controller I have:
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.js do
render(:update) { |page| page.reload }
end
end
end
The above code works perfectly. It deletes the record from the table and also reloads the page after clicking the destroy link. Now, my question is: can I do the same for updating a value in my record? If so, how can I do that?
Sure you can, you would simply change a few things:
The method in your controller would be update:
def update
#user = User.find(params[:id])
#user.update_attributes(params[:user])
respond_to do |format|
format.js do
render(:update) { |page| page.reload }
end
emd
end
Then you would change your link to something like the following:
<td><%= link_to "Update", my_path(user), :method => :put, :remote => true %></td>
Mind you, this is under the presumption that you are in a form_for #user tag.
<%= form_for #user do |f| %>
<%= f.text_field :name %>
# aforementioned link to update goes here
<% end %>
This is under the impression that you setup #user in the controller method (most likely def edit)
def edit
#user = User.find(params[:id])
end
Related
I have a user model established by Devise and it has a Boolean attribute "approved" with default value set to false.
I created a separate controller called "newcomers" where I set index action to display all not approved users and update action to set "approved" to true
class NewcomersController < ApplicationController
def index
#users = User.where("approved = ?", false)
end
def update
#user = User.find(params[:id])
#user.update_attribute :approved, true
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
end
So, in my view I did
<h1>Members Requests</h1>
<% #users.each do |user| %>
<%= user.email %>
<%= form_for user, url: newcomers_path, method: :patch do |f| %>
<%= f.submit "Approve" %>
<% end %>
<% end %>
and in my routes I have resources :newcomers
So, I do not know how to make the button work the way it should. Meaning it should just update the attribute "approved" and set it to true. and return to the same page (index)
Try following code
<h1>Members Requests</h1>
<% #users.each do |user| %>
<%= user.email %>
<% if user.approved %>
<%= link_to 'Unapprove', newcomer_path(user, approve: false), method: :put %>
<% else %>
<%= link_to 'Approve', newcomer_path(user, approve: true ), method: :put %>
<% end %>
controller
def update
#user = User.find(params[:id])
#user.update_attribute :approved, params[:approve]
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
Just use a link_to in your view an point it to the update action in your controller:
<%= link_to 'Approve', newcomer_path(user_id), method: :put %>
In your controller just update the user with the given id an redirect to index path as you already do.
If you want it somewhat more fancy you can add a remote: true to your link_to and respond with an js to delete only the affected row from your view.
Make below changes
In view
<%= form_for user, url: newcomer_path(user, approved: true), method: :patch do |f| %>
<%= f.submit "Approve" %>
<% end %>
and in controller
def update
if params[:user].nil?
#user = User.find(params[:id])
#user.update_attribute :approved, true
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
end
let me know if it is not working...
I'm running into a problem that I'm not exactly sure how to fix.
I have a simple to do list application with AJAX functionality on methods such as 'new', 'create', 'complete', 'delete', as well as Devise authentication.
When I first enter a new session with a User, all of these methods work without a problem. Additionally, the tasks are saved to only the user account, which is perfect.
However, when I log out of an account, and then log back in, the delete method no longer works. I receive the following error:
ActiveRecord::RecordNotFound (Couldn't find Task with 'id'=)
My tasks_controller.rb is below:
class TasksController < ApplicationController
def index
#task = current_user.tasks.all
end
def new
#task = Task.new
respond_to do |format|
format.js
format.html
end
end
def create
#task = current_user.tasks.new(task_params)
#task.save
respond_to do |format|
format.html
format.js
end
end
def update
#task = current_user.tasks.find(params[:id])
#task.toggle :complete
#task.save
respond_to do |format|
format.html
format.js
end
end
def destroy
#task = Task.find(params[:id])
#task.destroy
respond_to do |format|
format.js
format.html
end
end
private
def task_params
params.require(:task).permit(:id, :title, :complete)
end
end
I'm not exactly sure how to fix this problem. Would anyone have an idea on what is going wrong here?
EDIT:
I noticed that on my index page, I have a link to destroy the user's session at the top:
<%= link_to "Log Out", destroy_user_session_path, :method => :delete %>
I'm wondering if rails is having some trouble with this as both the logout link and the delete link are referencing the same method. If so, how can I change the name of the delete method for Task?
<div class="delete"><%= link_to "X", task_path(#task), method: :delete, remote: true %></div>
What is #task referencing? It looks to me like you've set #task to a collection #task = current_user.tasks.all.
Which would be why your delete method can't find a specific record to delete.
-EDIT-
Change #task in your index controller to #tasks as it is a collection.
In your view, do something like:
<% #tasks.each do |task| %>
<div><%= task.title %><div class="delete"><%= link_to "X", task_path(task), method: :delete, remote: true %></div></div>
<% end %>
The key here is that you have task_path(task) which is referencing a specific task id as opposed to task_path(#task) which is referencing a collection of tasks.
Fairly new to rails and can't seem to get this simple destroy action working. All it does is redirect to the mod panel index page and doesn't destroy the record. Do I need to call .destroy in the destroy method? or is there something I'm missing?
mod_approval controller
def index
#guide = Guide.friendly.find(params[:guide_id])
#check_category = CheckCategory.where(guide_id: #guide.id).all
#category = Guide.friendly.find(#guide.id).categories.new
end
def destroy
redirect_to guide_mod_panel_mod_approval_index_path(#guide)
end
config/routes.rb
match '/guides/:guide_id/mod-panel/approve/reject' => 'mod_approval#destroy', :via => :delete, as: :guide_mod_panel_approve_destroy
index.html.erb
<% #check_category.each do |category| %>
<%= link_to "Reject", guide_mod_panel_approve_destroy_path(#guide, category), method: :delete, data: {confirm: "You sure?"} %><br>
<% end %>
You need to fetch the record from the database, then you can call destroy on the object, you can do this
def destroy
guide = Guide.find(params[:guide_id])
category = guide.categories.find(params[:id])
category.destroy
redirect_to guide_mod_panel_mod_approval_index_path(guide)
end
Hope that helps!
You should have to destroy object before:
def destroy
#destroyed_object.destroy # or Model.destroy(params[:id])
redirect_to guide_mod_panel_mod_approval_index_path(#guide)
end
I'm trying to update a record in my Rails app using a button. I have a User and I want to update its school_id value. I have a School view page where a User can click on a button to add that school's id to the User school_id field. I'm struggling with the implementation. Here's what I have so far:
User controller:
def add_school
#user = User.find(params[:user_id])
#user.update_attributes(:school_id)
respond_to do |format|
flash[:notice] = "School has been added!"
format.html { redirect_to :back }
format.js
end
Button on School show page:
<%= button_to "Add School", add_school_user_path, :method => "put" %>
I tried to do this a different way by just adding code to the update action in the User controller but I couldn't get that to work either:
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:school_id])
flash[:notice] = "School has been added!"
redirect_to #user
end
if #user.update_attributes(params[:user])
flash[:notice] = "Successfully updated account and profile!"
end
end
What's the best way to pass the School's id into the User school_id column?
Thanks!!
EDIT 1: Routes
resources :users do
member do
get :following, :followers
put :add_school
end
Updated controller:
def add_school
#user = current_user
#school = School.find(params[:id])
#user.update_attributes(school_id: params[:school_id])
respond_to do |format|
flash[:notice] = "School has been added!"
redirect_to #user.school
end
end
Updated button link:
<%= button_to "Add School", add_school_user_path(#user, school_id: #school.id), :method => :put %>
Routing error:
No route matches {:action=>"add_school", :controller=>"users", :school_id=>1, :id=>nil}
You need a form for that instead of just abutton
<%= form_tag add_school_user_path(#user), method: put do -%>
<%= hidden_field_tag :school_id, #school.id -%>
<%= submit_tag 'Add school' -%>
<%- end -%>
you didn't provide the context code, maybe #user and #school are not the real variable names but you can get the idea from this
The provided answer is no longer entirely accurate. You can pass data and update a record with a button_to, so long as you aren't attempting to pass arbitrary data.
The button_to syntax would be something like this -- please note, this is my implementation of it, and it is not adjusted to your specific implementation as your controller would need additional adjustments from what you've specificed to accept certain params --:
<%= button_to "Mark Completed", todo_path(todo.id),
params: {:todo => { :id => todo.id, :completed => true, :user_id => current_user.id }},
method: :put, data: { confirm: "Mark this To-Do as being completed? This will hide it from view." } %>
You need to pass the whole hash into the call to .update_attributes.
Preferably, you will put school_id inside of user, so it will look like
# params[:user] = { school_id: 1 }
#user.update_attributes(params[:user])
Or you could code the school id manually
#user.update_attributes(school_id: params[:school_id])
Or, better yet, validate the association
#user.school = School.find(params[:school_id]
The path you would want is
user_add_school_path(#user, school_id: 1)
This is an old Q, but nevertheless for the sake of completeness. You do not necessarily need a form for a simple form-alike submission with a button/link. You can rely on jquery-ujs and data-params.
<%= link_to add_school_user_path(#user), class: "btn btn-xs btn-primary",
title: "Add school",
data: {remote: true, confirm: 'Are you sure?', method: 'put',
params: {user: {schoold_id: #school.id}}} do %>
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
Add school…
<% end %>
Note that you'd want to have school_params method in your controller akin to params.require(:user).permit(:school_id)
I have a user model and a question model.
In the user model:
has_many :questions
The question model:
belongs_to
in my questions/show.html.erb
<% if #question.user == current_user %>
<%= link_to 'Edit', edit_question_path(#question) %> | <%= link_to 'Destroy', #question, method: :delete, data: { confirm: 'Are you sure you want to delete this job?' } %>
<%= link_to 'Back', questions_path %>
<% else %>
<%= link_to 'Back', questions_path %>
<% end %>
How can only the user that authored the question edit and delete it?
Take a look at CanCan, the authorization gem by Ryan Bates of Railscasts. It's great for Rails authorization needs.
First, you'll create an Ability class that defines all of the abilities in the application.
class Ability
include CanCan::Ability
def initialize(user)
can :manage, Question, user_id: user.id
end
end
Then, you'll be able to easily integrate authorization into your controllers.
class QuestionsController < ApplicationController
def update
authorize! :manage, #question
...
end
def destroy
authorize! :manage, #question
...
end
end
And also customize your views.
<% if can? :manage, #question %>
<%= link_to 'Edit', edit_question_path(#question) %> | <%= link_to 'Destroy', #question, method: :delete, data: { confirm: 'Are you sure you want to delete this job?' } %>
<% end %>
All you need in your controller is:
def destroy
#question = current_user.questions.find(params[:id])
#question.destroy
render ... #anything you want to render
end
The previous code will ensure that an user can only delete his own questions. If the id of the question doesn't belongs to the user no question will be deleted and it would throw and ActiveRecord::RecordNotFound - Internal Server error. You can add a begin - rsecue block to catch this exception an handle it as you want.
def destroy
begin
#question = current_user.questions.find(params[:id])
#question.destroy
render or redirect_to ....
rescue Exception ActiveRecord::RecordNotFound
flash[:notice] = 'not allow to delete this question'
redirect_to ....
end
end
Other simple way is to add a before filter in your controller
before_filter :require_authorization, only: [:delete]
...
def destroy
#question = current_user.questions.find(params[:id])
#question.destroy
render or redirect_to ....
#With the before filter this code is only going to be executed if the question belongs to the user
end
...
private
def require_authorization
redirect_to :root unless current_user.questions.find_by_question_id(params[:id])
#Use the find_by to avoid the ActiveRecord::RecordNotFound and get a nil instead in case the question id doesn't belong to a question of the user
end
you can try changing your if to the following:
<% if current_user.questions.include?(#question) %>
Also you can take a look at :inverse_of
Then in your Edit and Delete actions in the controller you can again check for the right user before showing the edit form or deleting the question.