Call an action on button click in ruby on rails - ruby-on-rails

I have an action defined in my lib directory. The action is used to send a get request in the server. I want to execute the function on button click. How can I do this? I know this is not the right approach. I am new to rails.
show_document.rb (in lib directory)
class Legaldoc::ShowDocument
def view_document(sessionID, token_document)
require 'rest-client'
require 'zip'
res = RestClient::Request.execute(
:method => :get,
:url => "http://myurl.com",
:headers => {
:ldsessionId => sessionID,
}
)
end
end
in my view file
<%= link_to 'Button', '#', :onclick => "view_document(sessionID, token_document)" %>

I know this is confusing when you start developing in rails, but you have to consistently be very aware where your code is running. Your ruby code runs on the server, your html/js runs in the browser. Rails "prepares" html/js, but when you click a button, and you have to ask something from the server, you will have to use a url to acces a/any server.
Or you could resort to using javascript on the client directly, to fetch the data.
But since you already have the code in lib you will have to
add an endpoint, aka an action in a controller (add a new controller or add a new action in an existing controller, that is a bit hard with so little background information)
add a route to that controller/action
add the controller-code to call your lib function and format the answer in such a way relevant for the user
then add the button as follows:
<%= link_to 'Button', my_action_controller_path(session_id: sessionId, token_document: token_document) %>
(the name of the path depends on the names of controller/action, and you can see the names of the routes by running rake routes)
However your code seems to just fetch a page at myurl.com, so you could also just build a link to myurl.com ?
<%= link_to 'Button', 'http://myurl.com', target: '_blank' %>

Related

How to create a href tag with link_to and action 'create'

I want to create a href tag like href=contacts/create. In my contacts_controller, I have a create GET action. I know this is against rails convention. I still need to create the above link using options = {controller=> 'contacts', action=>'create'}. It works for any other arbitrary action name
You can the hardcoded path option:
<%= link_to "Create", "contacts/create" %>
or the Rails generated path option:
<%= link_to "Create", { controller: "contacts", action: "create" } %>
This is not just against Rails' convention, but against sounds HTTP usage. This often causes serious problems that you can't predict in advance. Web crawling is just one of them, where something like the Google bot accidentally creates a new contact in your database, simply by crawling the page. Or script kiddies who find you have a create link, and send 100,000 clicks to it in quick succession.
Numerous other issues happen like this, including, at one well-known time, Google Chrome pre-fetching GET urls from the page to "speed up the user experience"; this was felt far and wide by sites that had used this technique. It's not an idle warning or a style issue: this can have a disastrous impact on your site.
First off this is really bad idea since GET requests should be idempotent. You're not just flouting convention - you're setting yourself and your users up for a really bad time since for example pressing the back and forward buttons will cause resources to be created - over and over. And there is guaranteed a better way to solve whatever you are trying to do such as:
# a "discrete form"
<%= button_to "Create contact", contacts_path, method: :post %>
# or use the rails ujs
<%= link_to "Create contact", contacts_path, method: :post %>
If you ABSOLUTELY have do this:
Rails.application.routes.draw do
get "contacts/create"
end
You can now do:
<%= link_to "Create", { controller: 'contacts', action: 'create' } %>
Congratulations, you broke the internets.
Like you mentioned, this is against rails convention, but if absolutely necessary, you can do this from your controller:
options = {controller=> 'contacts', action=>'create'}
view_context.link_to url_for(options)
If you need the href to only be the path, you can do:
options = {controller=> 'contacts', action=>'create'}
view_context.link_to url_for(options.merge(only_path: true))

Rails - Change boolean value on link click

In my app I have user notifications where the user gets notified for certain actions. These notifications are being shown in a dropdown from the navbar (like Facebook or S.O.). All of the notifications have a boolean attribute called :read and are default set to false. I'm using bootstrap with the dropdowns (in case that helps).
I want to create a method where when the user clicks to open the dropdown, all of their unread notifications become read.
Here is what I have so far for the method.
def read_notifications
PublicActivity::Activity.where(recipient_id: current_user).where(read: false).update_all(:read => true)
end
This updates all of the current user's notifications to :read => true when the method is called. In the view here is what I had so far for the dropdown link.
<%= link_to read_notifications_path, :class => "dropdown-toggle notifications_icon", :'data-toggle' => "dropdown", :controller => "application", :action => "read_notifications", :method => :post do %><% end %>
and the routes.rb I had this.
match "/read" => "application#read_notifications", :as => "read_notifications", via: 'post'
Now I know what I have is wrong, but even so when I click the link it does switch all of the user's notifications to read, it just acts also as a link (duh) and goes to a different page.
As you know, the link on a bootstrap dropdown is "#".
Does anyone know how I can set this up properly where when the user clicks the notification link in the navbar, ALL it does is open the dropdown and change the boolean value to true for all notifications.
I know this is possible, I just haven't been able to figure it out yet.
Thanks for taking a look at it.
EDIT
JS file
$(".notifications_icon").on("click", function(){
$.post("/read", function(data){
$('.notification_badge').text("");
});
});
View
<%= link_to "#", :class => "dropdown-toggle notifications_icon", :'data-toggle' => "dropdown" do %>
<span class="notification_badge"><%= find_unread_notifications_count(current_user) %></span>
<% end %>
This is Posting to the /read to read all of the notifications but it's not updating the count
You want a dash of unobtrusive JS. For example, SO has a class js-inbox-button that, when clicked, triggers updates on unread counts (both client and server). I won't dig into their JS source, but it's fairly simple to build.
You seem to already have a relevant class (notifications_icon), though you might want to use something else. When the link is clicked, use jquery $.post.
$(".notifications_icon").on("click", function(){
$.post("/read", function(data){
// remove unread count
$('.notification_badge').text('');
});
});
Now this is a very basic implementation. Couple of suggestions:
Only make requests when necessary (check for unread count on page first)
Use a data attribute on the link to pass /read path. That way you can still use your path helpers instead of hardcoding a path.
Store the above JS in a separate file (unobtrusive)
AJAX.
By adding remote: true you're starting with AJAX. Now the call goes to your path, and nothing happens! yay!
You want something to happen, though. So in your controller (I wouldn't do it in the application_controller, if I were you... activities_controller.rb maybe?):
controllers/activities_controller.rb
def read_notifications
PublicActivity::Activity.where(recipient_id: current_user).where(read: false).update_all(:read => true)
respond_to do |format|
format.js
end
end
You're on your way to Asynchronous loading! Now you need a js file to match it. So, since you've already moved this action to the activites, in your view, you'll have a new js.erb file to create (notice that it's in the same folder in the views as the controller name, and the file is named after the action):
views/activities/read_notifications.js.erb
$('#your_menu_div').html("<%= j render partial: 'activities/notifications' %>");
Now you create a partial (views/activities/_notifications.html.erb) that gets rendered into your pulldown menu.
Clear as mud?

System call from method (ruby on rails)

I need make system call from method of Ruby of Rails , but I want it to stay on the same page.
Right now for some reason it does not execute , but shows :
Routing Error
No route matches [POST] "/devices/22918"
Try running rake routes for more information on available routes.
This is the button:
<%= link_to image_tag("/images/glossy_green_button.png"), device , :method => :turnon, :confirm => "Are you sure?" %>
This is method:
def turnon
#device = Device.find(params[:id])
result = `/perl/toggle.pl #device.infodot on`
end
please let me know what I am doing wrong,
thank you
D
You're simply not using the method correctly. You're using it to target the action of the controller you want to execute (note that I explicitly said action and not method for clarity).
Available actions in a controller are defined by your routes.rb file.You should eventually read or re read that
In your case, let's say you have a resource device (I guess this is what you have), you'll first create a new action in your routes.rb file
resources :devices do
put :turnon, on: :member
end
You can read doc about this syntax here but basically I'm making the action turnon available via the HTTP PUT method on each devices, meaning that it will be accessible through the URL /devices/1/turnon or via the url_helper : turnon_device_path (or turnon_device_url)
I assume that your turnon action will modify existing things, not creating new things, that's why I'm using the PUT verb
Then the link will look something like :
<%= link_to image_tag("/images/glossy_green_button.png"), turnon_device_path(device) , :method => :put, :confirm => "Are you sure?" %>
see that the method is the HTTP method corresponding to the new route I created.
I also assume that you put the turnon method in the DevicesController.
Finally as you want to do that in ajax, you can have a look a the remote: true option

calling a ruby function from rails - it takes to a view which I don't want

I want to make a ruby function called within rails. I followed this question, but I get redirected to
http://localhost:3000/my_func?arg=arg
which I don't want. I only want to execute the function when the button is clicked, but remain on the same page!
EDIT:
I modified the code, or better yet, made a scratch site just to solve this. I only did:
rails new eraseme
cd eraseme
rails g controller public home
app/controllers/public/home.html.erb
class PublicController < ApplicationController
def home
end
def my_func
end
end
app/views/public/home.html.erb
<%= button_to "Button", {:action => "my_func", :arg => "arg"} %>
What I want to do, is execute my_func when I click the button. But when I click, I get
No route matches {:action=>"my_func", :arg=>"arg", :controller=>"public"}
So, from what I can tell. I think you want to make a button that will send an AJAX/HTTP request to the Controller in order to call a function, that won't return a HTML file at completion.
In order to accomplish this, you must do the following.
1.) Set the HTTP routing for this call, this is within the config/routes.rb file.
match '/public/my_func' => 'public#my_func'
This allows your application to direct any HTTP requests with the following URL to call your method within the controller. Your button_to method will send this call with that URL due to the :action => "my_func" param.
2.) Also include the :remote => true, :form => { "data-type" => "json" } as more parameters to the button_to method.
This will transform the button from a traditonal HTTP request to an HTTP Request via AJAX request.
Let me know how this works, I think there are alternatives to using AJAX in this case, if its a very simple method then you can perhaps include it within the view as erb.

Ruby on Rails: link-to using post method but parameters are in the URL

I'm using
link_to 'My link', path(:arg1 => session[:arg1], :arg2 => session[:arg2],:arg3 => anyobject.id), :method => :post
but the HTML link being generated includes (arg1,arg2,arg3) as URL query parameters.
How can remove them? Did I miss something in the documentation?
A link_to will always put the arguments into the query string as it is creating a get-style HTML link - even if you put :method => :post that just appends an extra ("special") argument _method.
What I think you really want is a button_to link - which will make it into a sort of form-post. It works the same, but it says button_to instead (for example, button_to 'My link', path(:params => :go_here). The downside is that it will look like a button. But you can give it a CSS class (eg "unbutton") and then change the styling on that CSS class to make it not look like a button.
Alternatively, if what you really want is actually to have no params passed to the controller at all... then just don't include them when making your link (for example, link_to "My link" path - there's no need for :post if you don't want to post any params).
Finally, if what you want is for the params to become a part of the URL (for example, stuff/[param_1]/more_stuff/[param_2], etc.) then you need to update your routes to include these parameters as options. Have a look at the routing section of the rdoc for how to do that.
You can use below code, which rails.js need data-method to switch to post mode in Ajax.
<%= link_to '<button id="print" type="submit" class="btn">Print</button>'.html_safe, { controller: :lots, id: #lot.containername, action: "print_#{print_template}", remote: true }, {'data-method' => :post} %>

Resources