using button_to to link to a method, can it be done? - html

is it possible to link to a method inside a different model? To execute on button press, or is there another way of doing this, something like an action in a controller?
Method inside staff model:
def clearleave
self.where("grade = '1'").update_all(:leave_balance => 22)
self.where("grade = '2'").update_all(:leave_balance => 25)
self.where("grade = '3'").update_all(:leave_balance => 30)
self.where("grade = '4'").update_all(:leave_balance => 35)
end
inside a view for a different model:
<%=button_to "Clear absences", {:controller => :staffs, :action => :clearleave} %>

Rails bases on the Model View Controller pattern (MVC). This means, that requests (e.g. trough the browser) are handled by your controllers. Controllers will collect the required data from the models and pass it to the views for display.
What you are probably aiming for is something like this:
Routes:
resources :staff do
member do
post :clearleave
end
end
Controller:
# StaffController
def clearleave
#staff = Staff.find(params[:id])
#staff.clearleave # this calls the method in your model
# here you could redirect to e.g. the show page for your staff
# redirect_to staff_path(#staff), :notice => "Cleared successfully"
end
Your button in the view would be:
<%= button_to "Clear absences", clearleave_staff_path(#staff) %>
<!-- not sure if a ", :method => :post" is required here as well -->
<!-- in rails 3 a link_to should also work -->
<%= link_to "Clear absences", clearleave_staff_path(#staff), :method => :post %>

Related

Getting a button to add current user's id to a field

I'm trying to get a simple button press that will store current user's id into a field but getting an error that says
ActionController::ParameterMissing (param is missing or the value is empty: request):
Here's my code.
The button code
<%= form_for(request.accept, remote: true) do |f| %>
<%= f.submit "Accept", class: "btn btn-primary" %>
<% end %>
request_controller
def accept
#request.ssp_id = current_user.id
#request.save
flash[:success] = "The request have been accepted!"
end
Thanks in advance.
The ParameterMissing error is probably because you have specified to require request model in your parameters through strong_params.
Since you are trying to update an existing record with the current_user you don't need a form.
Update your accept action in the RequestsController:
def accept
#request = Request.find params[:id]
if #request.update_attribute(:ssp, current_user)
redirect_to requests_path
flash[:success] = "The request have been accepted!"
end
end
Request model
class Request < ApplicationRecord
belongs_to :ssp, class_name: "User"
end
And your routes:
resources :requests do
member do
get "accept"
end
end
<%= link_to 'Accept request', accept_request_path(request) %>
Also as a recommendation try to use a different name for your model since the word request is wide use in Rails. I don't know if this could be a problem latter on.

Rails + AngularJS + Not able to access all the columns of the Single Model at View

In my rails application, I am trying to fetch Logged-In-User details using AngularJS service. But while accessing the JSON from server I am getting only few columns rather than all the column present in model.
Only FirstName, LastName, and Primary Email is visible on page and rest of the column are empty.
I tried by direct hit of URL : http://www.example.com/LoggedInUserInfo.json
Output : {"first_name":"User","last_name":"1","primary_email":"user_one#mailinator.com"}
User Model
class User < ActiveRecord::Base
attr_accessible :blood_group,:city,:country,:first_name,:gender,:mobile_number,
:phone_number,:primary_email,:secondary_email,:state,:street_address,
:street_address2, :username, :zip_code
Controller Method
def logged_in_user_info
#user = User.find(1)
render :json => #user
#render :json => #user.as_json(:only => [:first_name, :last_name,
# :username, :date_of_birth])
end
AngularJS Service
var user_app = angular.module("UserApp", []);
user_app.controller("LoggedInUserInfoCtrl", function($scope, $http) {
$http.get('/LoggedInUserInfo.json').
success(function(data, status, headers, config) {
$scope.logged_in_user = data;
}).
error(function(data, status, headers, config) {
// log error
});
});
Routes
match '/LoggedInUserInfo' => 'dashboard#logged_in_user_info', :via => [:get]
Please suggest some thing to bring all the columns. I think every thing has to be done with Rails Controller. Thanks in advance.
After a lot of googling and lot of changes in controller, got the way to render or fetch specific column at view.
Just created a helper function so that we can call from the view to rearrange or reformat the output that we are calling from the controller. And problem resolved.
def logged_in_user_info
#user = User.find(1)
respond_to do |format|
format.html
format.json do
render :json => custom_json_for_user(#user)
end
end
end
private
def custom_json_for_user(user_data)
user_list =
{ :id => user_data.id,
:first_name => user_data.first_name.to_s,
:last_name => user_data.last_name.to_s,
:date_of_birth => user_data.date_of_birth.to_s,
:username => user_data.username,
:primary_email => user_data.primary_email,
:secondary_email => user_data.secondary_email,
:gender => user_data.gender
}
user_list.to_json
end

Routing Error in Rails No route matches {:action=>"ticket_action", :controller=>"tickets"}

This is an error I can not seem to figure out I believe I have it routed. This is the error
No route matches {:action=>"ticket_action", :controller=>"tickets"}
I get this error after this code
<h4>New Action</h4>
<% form_tag :action => 'ticket_action' do %>
<p><b>Description</b><br/>
<%= text_area 'description', 'description', 'rows' => 5 %><br/>
User: <%= select("actUser", "user_id", User.find(:all).collect{|u| [u.name, u.id] } )%>
<% end %>
I have this on my ticket_controller.rb is that the proper placement for that
#action
def ticket_action
#act = Action.new(
"ticket_id" => flash[:ticket_id],
"description" => params[:description]['description'],
"user_id" => params[:actUser]['user_id']
)
routes
actions GET /actions(.:format) actions#index
POST /actions(.:format) actions#create
new_action GET /actions/new(.:format) actions#new
edit_action GET /actions/:id/edit(.:format) actions#edit
action GET /actions/:id(.:format) actions#show
PUT /actions/:id(.:format) actions#update
DELETE /actions/:id(.:format) actions#destroy
tickets GET /tickets(.:format) tickets#index
POST /tickets(.:format) tickets#create
new_ticket GET /tickets/new(.:format) tickets#new
edit_ticket GET /tickets/:id/edit(.:format) tickets#edit
ticket GET /tickets/:id(.:format) tickets#show
PUT /tickets/:id(.:format) tickets#update
DELETE /tickets/:id(.:format) tickets#destroy
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
clients GET /clients(.:format) clients#index
POST /clients(.:format) clients#create
new_client GET /clients/new(.:format) clients#new
edit_client GET /clients/:id/edit(.:format) clients#edit
client GET /clients/:id(.:format) clients#show
PUT /clients/:id(.:format) clients#update
DELETE /clients/:id(.:format) clients#destroy
It would be helpful to post the route to debug this problem, your route may refer to tickets yet your class is ticket.
You should look into restful routes, especially given your use case. It seems you should really have an actions controller (ActionsController, named controllers/actions_controller.rb) and then post to the create action and provide a restful route (resources :actions)
My suggestion would be to read up on rest and rails first.
Additionally the flash isn't where you should store your ticket_id, ideally you should retrieve it in your actions controller's create action by posting to /action/ticket_action/1 and retrieving the id by accessing params[:id] in the controller. If you really must, store it in the session (session[:ticket_id] = "1") but 'rest' is where you should be headed. The flash will be removed and should only be set in the controller and then displayed on the next page, it will be deleted thereafter.
Update: ok thanks for posting your routes.
You can add the missing route like this if you want:
resources :tickets do
member do
post 'ticket_action'
end
end
But it would be better to follow this pattern:
In actions controller:
def new
#action = Action.new
end
Your form should look a bit like this, Rails will know to post to actions#create because #action is a new record (you can check #action.new_record? if you want)
<%= form_for #action do |f| %>
<%= f.text_area :description, :rows => 5 %>
<%= f.hidden_field :ticket_id, flash[:ticket_id] %>
<%= f.select :user_id, User.find(:all).collect{|u| [u.name, u.id] } %>
<%= f.submit "Create" %>
<% end %>
Then in your actions controller:
def create
#action = Action.new(params[:action])
end
or with less magic:
def create
#action = Action.new(:user_id => params[:action][:user_id],
:description => params[:action][:description],
:ticket_id => params[:action][:ticket_id])
if #action.save
redirect_to actions_path(#action, :notice => "Created action")
else
render :new # any errors will be in #action.errors
end
end
You should really be setting the ticket_id in the actions controller's new method though.
def new
#action = Action.new(:ticket_id => params[:ticket_id])
end
And then in your form:
<%= f.hidden_field :ticket_id %>
Your file name should be "tickets_controller.rb", plural.

Making AJAX requests in Rails without a form

So I have a posts scaffold generated in a Rails app and I've added an upvote and downvote column to the post model. I added an "upvote" button on the view file and I need to make an AJAX call and query the database when you hit the upvote button, but the upvote button has no real Rails <form> attached to it. How can I make this AJAX call and add the upvote to the database for the upvoted post?
When I make this AJAX call:
$('.up,.down').click(function(){
$.ajax({
type: 'POST',
url: '/posts',
dataType: 'JSON',
data: {
post: {
upvote: 1
}
},
success: function(){
alert('success')
}
});
});
It returns a 500 error. Where do I go form here?
You could use the :remote => true attribute on the link_to helper
for example:
<%= link_to post_upvote_path(post), :remote => true, :method => "put" %>
<%= link_to post_downvote_path(post), :remote => true, :method => "put" %>
then in config/routes.rb:
resources :posts do
put "upvote", :to => "posts#upvote", as: :upvote
put "downvote", :to => "posts#downvote", as: :downvote
end
then handle the voting in your posts controller, like you probably already are and grab the post id with params[:id] in the action
Here is an intro to rails flavored unobtrusive javascript
Update
To see the upvote and downvote routes that were created, go to the terminal and type
rake routes | grep vote
this will give you a list of all of your routes that have "vote" in the name. Or just type rake routes to get a list of all of them. The first column is the named route, just append '_path' to the end of it to use it in your app - like post_upvote_path above would be seen as
post_upvote PUT /posts/:id/upvote(.:format) posts#upvote
And in you PostsController you would want these actions:
class PostsController < ApplicationController
###
# index, show... other RESTful actions here
###
def upvote
#post = Post.find params[:id]
# code for however you are voting up the post here
end
def downvote
#post = Post.find params[:id]
# code for however you are voting down the post here
end
end

add comparison feature in rails

i'm having a bit of trouble with adding a certain feature. i'm working on a buy/sell site and i want to be able to compare posts. here's what i have so far:
in the posts view:
<%= button_to "Add to Compare", :action => "addCompare" %>
in the corresponding controller:
##a = Array.new()
def addCompare
##a << Post.id
end
so, all i want to do is add the post's id to the array ##a. when i test this, i click on the "Add to Compare" button and I'm welcomed with this:
Template is missing
Missing template posts/addCompare with {:locale=>[:en, :en], :formats=>[:html], :handlers=>[:rxml, :rjs, :builder, :rhtml, :erb]} in view paths "/home/mja32/470repo/traders/app/views", "/var/lib/gems/1.8/gems/devise-1.4.2/app/views"
So I guess it's trying to redirect to a view. How do I prevent it from doing this? All I want this button to do is to add the post's id to the array and nothing more.
Thanks in advance,
Matt
First of all, storing persistent data in a controller's class variable isn't going to work the way you want it to. There's no guarantee that ##a will be the same array on your next addCompare call; for example, your next addCompare call could be handled by a different process. Also, what happens if two different clients call addCompare? Do you really want to mix their data together in one pile? Probably not. Your first task is to replace ##a with a real per-user persistent store.
If you want to return nothing at all from your controller, just do this at the end of your controller method:
render :nothing => true, :status => :ok
That will tell Rails that something has already been rendered so it doesn't need to try the default rendering action (which is to render the posts/addCompare view) and returns nothing more than a 200 status code to the client.
Once that's in place, you'll probably want to AJAXify your button with :remote => true:
:remote - If set to true, will allow the Unobtrusive JavaScript drivers to control the submit behaviour. By default this behaviour is an ajax submit.
So this:
<%= button_to "Add to Compare", { :action => "addCompare" }, { :remote => true } %>
Note that button_to looks like this:
button_to(name, options = {}, html_options = {})
and that :action is for options but :remote is for html_options so you have to explicitly set up the hashes with {}; you could just wrap the options in braces:
<%= button_to "Add to Compare", { :action => "addCompare" }, :remote => true %>
but I prefer the consistency of wrapping them both by hand.