Update a record with a button in Rails? - ruby-on-rails

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)

Related

In Rails, how do I create one single search form with multiple buttons, each routed to a different controller?

In my view, I want to create one single search field with two buttons. Once I click the first one I want to use the string in the search field for searching for Users. When I click the second button I want to use the string in the field for searching for posts.
I think a solution whould look something like this:
<%= form_tag([users_path, posts_path], method: 'get', id: 'search-form') do %>
<%= text_field_tag(:search, params[:search], id: 'search-field', placeholder: "Search") %>
<%= button_tag(:id => "search-user-btn", :controller => :users) do %>
<i class="icon-search-user"></i>
<% end %>
<%= button_tag(:id => "search-post-btn", :controller => :posts) do %>
<i class="icon-search-post"></i>
<% end %>
<% end %>
Is it possible to have one text_field and share it for two buttons routed each for a different controller (users and posts in this case)?
How can I do this?
In the view:
<%= form_tag([users_path, posts_path], method: 'get', id: 'search-form') do %>
<%= text_field_tag(:search, params[:search], id: 'search-field', placeholder: "Search") %>
<%= submit_tag 'Option1' %>
<%= submit_tag 'Option2' %>
<% end %>
You can add the code in the current controller for each Submit button like this:
def create
#user = User.new(user_params)
if params[:commit] == 'Option1'
# code for Option1
elsif params[:commit] == 'Option2'
# code for Option2
end
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
If you want a direct answer, you'll be able to use the following:
<%= text_field_tag :search, params[:search], id: 'search-field', placeholder: "Search" %>
<% %w(posts users).each do |option| %>
<%= button_to "Search #{option.titleize}", eval("#{option}_path"), id: "search-#{option}-btn", method: :get, params: { search: "" } %>
<% end %>
You'd then be able to use some JS to fill out the button_to hidden search fields whenever you change the "main" search:
#app/assets/javascripts/application.js
$(document).on("keyup", "#search-field", function(){
val = $(this).val();
$("#search-posts-btn").val(val);
$("#search-users-btn").val(val);
});
When submitted, each button_to will yield the respective search value.
--
An alertnative method, as mentioned by hugo is to send all the requests to a single controller action, processing the data as required.
Hugo's answer is pretty epic, but there's a small change I would make:
#config/routes.rb
get "search(/:search)", to: "application#search"
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def search
if params[:search]
case params[:search][:commit]
when "option1"
# Search users
when "option2"
# Search posts
end
end
end
end
This will allow you to use the form that Hugo provided, sending the entire form data to /search for processing.

How to pass parameters with form_for to controller ruby on rails

I have a user model and a course model, and user can upload courses for themselves after they login.
However, I want admin to be able to upload for users to in case the user is not savvy enough.
My thought was to use the same create action for both user-upload and admin-upload, with an if statement.
The admin will select the user before he uploads for him in users/:id view page:
<%= link_to 'Upload Course for User', new_course_path(user_id: params[:id]), class: 'btn btn-primary' %>
Then I was able to see the create page with the parameter:
http://localhost:3000/courses/new?user_id=10
and I submit this form
<%= form_for(#course, html: {class: "form-group"}) do |f| %>
...
<%= f.submit "Create Course", class: 'btn btn-primary' %>
to the create action in the controller:
def create
#course = Course.new(course_params)
#course.user_id = params[:user_id] || current_user.id
if #course.save
redirect_to course_path(#course), notice: 'The course has been created successfully!'
else
render 'new'
end
However I'm never getting the user_id params, always just the current_user.id, which is the admin_user's id and that's not good.
How do I manage to pass in the user_id parameter to the controller create action so that it knows I'm trying to create for another user, not myself? Is there a better way to handle this than my logic?
Thanks!
You can try this.
in Form.
<%= form_for(#course, html: {class: "form-group"}) do |f| %>
<%= hidden_field_tag "course[user_id]", "#{#user_id}" %>
<%= f.submit "Create Course", class: 'btn btn-primary' %>
In controller create method.
def new
#user_id = params.has_key?("user_id") ? params[:user_id] | current_user.id
##OR
##user_id = params[:user_id] || current_user.id
end
def create
#course = Course.new(course_params)
## OR
##course.user_id = params[:user_id] || current_user.id
if #course.save
redirect_to course_path(#course), notice: 'The course has been created successfully!'
else
render 'new'
end
end
private
def course_params
params.require(:course).permit(:user_id)
end
<%= f.hidden_field :user_id, :value => params[:user_id] %>
So it will be passed as form element

Creating a button to make user an admin

I am doing Hartl's tutorial and I want to make other users admins. Can I create a button that links to a action that updates the user's attributes to make them an admin?
<%= button_to "Make Admin", {action: "make_admin" }, method: :put %>
Users controller
def make_admin
update_attribute(:admin, true)
redirect_to users_url
end
routes.rb
put 'admin' => 'users#make_admin'
Had trouble referencing the right user. Any suggestions or a sure-fire way?
Thanks
Route is missing an :id. Change it to
put 'admin/:id' => 'users#make_admin', :as => "make_admin"
Also, for button_to:
<%= button_to "Make Admin", {action: "make_admin", id: current_user.id }, method: :put %>
and UsersController:
def make_admin
user = User.find params[:id]
user.update( :admin => true )
redirect_to users_url
end

Ruby on Rails Page not reloading on submit button click

I have an Approve button that changes status attribute of the Shop table record. When I click on it, it does change attribute, but it doesn't reload the page, so I have to reload page manually to see the result, which is very inconvenient. Looks like everything has to work, but page still not reloading.
My view has:
<%= form_for([:admin, #shop], remote: true, data: { confirm: "You sure?" }) do |fr| %>
<%= fr.hidden_field :status, :value => 2 %>
<%= fr.submit "Reject", class: "btn btn-large btn-danger" %>
<% end %>
And the controller:
def update
#shop = Shop.find(params[:id])
if #shop.update_attributes(shop_params)
flash[:success] = "Shop updated"
redirect_to([:admin, #shop])
else
render 'edit'
end
end
I would be grateful for any help, thank you!
You are using remote: true in form_for, which is making your form submission via AJAX.
You may need to add method: :put so that form hits action update instead of create.
So just try removing remote: true and add method: :put as follow and try submitting form again.
<%= form_for([:admin, #shop], method: :put, data: { confirm: "You sure?" }) do |fr| %>
<%= fr.hidden_field :status, :value => 2 %>
<%= fr.submit "Reject", class: "btn btn-large btn-danger" %>
<% end %>
maybe you are missing the respond_to do |format| calls or did you omitted them on the question?
should be like that:
def update
#shop = Shop.find(params[:id])
respond_to do |format|
if #shop.update(shop_params)
format.html { redirect_to [:admin, #shop], notice: "Shop updated"
else
format.html { render action: 'edit' }
end
end
end
hope that helps.

Updating a record with Rails remote function

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

Resources