System call from method (ruby on rails) - 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

Related

ActionController::UrlGenerationError using link_to

I have a controller Posts in which I have a method:
def report_user
...
end
I have a view where I would like a link that will perform some logic (it should NOT actually take the user to a different page, only perform the logic and possibly show a dialog box after completion). The logic is contained in the report_user action in the Posts controller:
<%= link_to "Report User", :controller => :Posts, :action => :report_user %>
I would ultimately like to pass some variables also to the report_user action, however I haven't gotten that far as I've come across this error:
No route matches {:action=>"report_user", :controller=>"Posts"}
message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
raise ActionController::UrlGenerationError, message
end
I'm not sure what the issue is. There is definitely an action in the Posts controller called report_user and it is not private. I'm not sure what the missing required keys means either. I've seen on SO other people with that error, but they all have routes defined that require parameters. I do not have any routes defined for this. Possibly I"m going about the entire thing in the wrong way?
As Nils suggested, you need an entry in routes.rb. Assuming that this is a member route using a GET request, that entry would look like this.
resources :posts do
get :report_user, on: :member
end
Next, you need to update your link to use the routing helpers that Rails provides.
<%= link_to "Report User", report_user_post_path(#post), remote: true %>
I included the remote: true option b/c you mentioned that clicking the link shouldn't reload the page. The default response for this request will be app/views/posts/report_user.js.erb.
I would encourage you to read up on Rails routing at http://guides.rubyonrails.org/routing.html.

link_to custom action but wrong method?

all, I'm trying to get a custom action to work with a put method: in the
in _post.html.erb i have a link_to statement:
<%= link_to 'End now', post, :method => :put, :action => endnow %>
routes.rb contains:
resources :posts do
member do
put :endnow
end
and posts_controller.rb looks like:
class PostsController < ApplicationController
helper_method :endnow
[.. code for create, edit, destroy, etc ..]
def endnow
puts params
end
end
rake routes's relevant line looks like:
endnow_post PUT /posts/:id/endnow(.:format) posts#endnow
However, the action endnow helper doesn't run when clicking on this link.
Strangely, it does run with an index action (which i can tell from the puts command.
Of course, eventually the code for endnow will update #post, but for now, it just doesn't run properly.
Maybe i'm going about this the wrong way - all I'm trying to achieve is to update #post upon clicking the link to that post, and before showing it.
Any ideas / Alternatives?
Why not use the route helper method provided to you? Change your link to
<%= link_to 'End now', endnow_post_path(#post), method: :put %>
Things you're doing wrong:
If you want to specify the :action, use the Symbol for the action (you're missing a colon). :action => endnow should be action: :endnow
I will assume you have a #post instance variable you're passing from your controller to your action. You should be using that instead of post (unless you do in fact have a local post variable you're omitting from your code)
You are using endnow as an action; you should remove the helper_method :endnow line in your controller because it's not something you want to/should be accessing from your view.
This can all be avoided by using the route helper (for endnow_post you'd append _path to get the local route path: endnow_post_path), and pass in your #post as an argument.
Because you're trying to do a PUT request, you must make sure you have something like jquery-ujs included in your asset pipeline to convert these links to form submissions behind the scenes; browsers don't support PUT via the click of a link on their own.
As for why you're getting the template error when you get your link_to working, Rails is telling you that you need to create a app/views/posts/endnow.html.erb file. Your action has only puts params which does not terminate execution, leaving Rails to assume you still are trying to render some endnow.html.erb template.
Are there other ways to do what you're trying to do (change a single attribute of a specific model)? Sure. Are there better ways? That's pretty subjective; it may not be the most RESTful way, but it's arguably easier to deal with (if for example there are very specific authorization rules to check before updating the attribute you are modifying in endnow. Does the way you've started fleshing out work? Absolutely.
Finally, as a bump in the right direction, after you fix your link_to and remove the the helper_method as I have described above, your endnow action might look like this:
def endnow
post = Post.find!(params[:id])
post.some_attribute_here = some_new_value_here
post.save
redirect_to :root and return # <- this line sets a redirect back to your homepage and terminates execution, telling rails to do the redirect and **not** to render some endnow.html.erb file
end

Ruby on Rails: How to print out a string and where does it display at?

I know this is a trivial question. But I have search all over google but cannot find a simple answer to this question.
Basically I have a line that says <%= link_to 'Run it', :method => 'doIt' %> in the view, then in the corresponding controller, I have the doIt method as follows:
def doIt
puts "Just do it"
end
I just want to check that if i click on Run it, it will output the string "Just do it". I ran this on localhost and there is no errors, but I can't find the output "Just do it" anywhere. It is not displayed in the rails console or rails server log. I just want to know where does puts output the string to , where to find it ?
Round 2: So this is what I tried ....
Added this line in the index.html.erb (which is the root)
<%= link_to 'Run it', :method => 'do_it' %>
and in the url, it is just basically http://localhost:3000/ (since i route controller#index as root)
The display is just an underlined 'Run it' that links to 'do_it' method in the controller.
In the controller, i include this method
def do_it
logger.debug "Just do it"
end
when i click on 'Run it', the url change to http://localhost:3000/gollum_starters?method=do_it and in the development.log, the following is written into it:
Started GET "/gollum_starters?method=do_it" for 127.0.0.1 at 2011-08-25 15:27:49 -0700
Processing by GollumStartersController#index as HTML
Parameters: {"method"=>"do_it"}
[1m[35mGollumStarter Load (0.3ms)[0m SELECT "gollum_starters".* FROM "gollum_starters"
Rendered gollum_starters/index.html.erb within layouts/application (3.6ms)
Completed 200 OK in 16ms (Views: 7.7ms | ActiveRecord: 0.3ms)
Additionally, i tried all the logger.error/info/fatal/etc ... and Rails.logger.error/info/fatal/etc, all did not print out the line "Just do it" in the development log
#Paul: I did not touch the environment folder or file, i assume by default when a new rails app is created, it is in development ?
#Maz: Yes you are right, I am just trying to test if the do_it method is getting called. To do that, I just want to print something out in the controller. Can't think of any way simpler that just print a string out, but this problem is making me miserable. I am just using textmate, no IDE.
Round 3:
#Paul thx alot, but i encountered error
My routes files is now:
resources :gollum_starters
root :to => "gollum_starters#index"
match 'gollum_starters/do_it' => 'gollum_starters#do_it', :as => 'do_it'
My index.html.erb is now:
<%= link_to "Do it", do_it_path %>
My gollum_starters_controller.rb
def do_it
logger.debug 'Just do it'
end
I am getting this error:
Couldn't find GollumStarter with ID=do_it
the error is in here, 2nd line:
def show
#gollum_starter = GollumStarter.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #gollum_starter }
end
end
I wonder why does it route to show ? When i click do_it, it actually goes to localhost:3000/gollum_starters/do_it which is correct, but apparently the error points to the show method ?
Round 4:
#Paul, i shifted resources :gollum_starters down:
root :to => "gollum_starters#index"
match 'gollum_starters/do_it' => 'gollum_starters#do_it', :as => 'do_it'
resources :gollum_starters
but got this error (omg i wanna kill myself),
Template is missing
Missing template gollum_starters/do_it with {:handlers=>[:erb, :rjs,
:builder, :rhtml, :rxml], :formats=>[:html], :locale=>[:en, :en]} in
view paths "~/project_name/app/views"
:/
---------- Answer to Round 4 ------------
Basically as the error explains, there is no template(i.e a webpage) to show hence error thrown. The solution is to add a redirect_to , in this case I redirect to root_url.
def do_it
logger.debug 'Just do it'
redirect_to(root_url)
end
Everything works now, "Just do it" finally outputs to development.log and the rails server console.
Thank you Maz and Paul and Andrew for helping me out. Learn a lot.
That link_to does not do what you think it does the value for :method is referring to the HTTP verbs.
Taken from the docs for ActionView::Helpers::UrlHelper
:method - Symbol of HTTP verb. Supported verbs are :post, :get, :delete and :put. By default it will be :post.
You would need to define a route in your routes.rb file that uses your method
# The order of routes is important as the first matched will be used
# therefore the match needs to be above 'resources :controller'
match 'controller/do_it' => 'controller#do_it', :as => 'do_it'
resources :gollum_starters # <--- This needs to be below the match or this will catch first
The controller/do_it is the route to be matched
The controller#do_it is the controller followed by the action to be used (separated by #)
The value for :as creates the path do_it_path that can be used in your link_to
Your link_to may look something like
<%= link_to "Do it", do_it_path %>
And to complete the lifecycle of a request you will need to add a view to be rendered
app/views/gollum_startes/do_it.html.erb # <-- Add file
Summary
Doing all of this creates a bit of a mess just to print something out to the logs, but it should help you understand the whole lifecycle a bit better now. Plus this answers serves as a document to help you rewind this mess.
You are not understanding what "method" means in the context of a link.
The "method" here refers to the request method, which means the kind of request you are asking the browser to make. From the perspective of a RESTful application like Rails there are four relevant request types: GET, POST, PUT, and DELETE. These request types affect how the controller responds to a request.
GET => INDEX or SHOW
POST => CREATE
PUT => UPDATE
DELETE => DESTROY
There are two other "standard" rails actions, NEW and EDIT. These are GET requests to present an interface to the user. NEW gives you a form to POST (CREATE) a new object, and EDIT gives you a form to PUT (UPDATE) and existing one.
See the rails guide for more on how HTTP Verbs relate to CRUD operations.
The important, basic thing to understand is that links, by default, are GET requests, and forms, by default, are POST requests.
So, when your link looks like this:
<%= link_to 'Run it', :method => 'do_it' %>
...it is bogus. There is no such HTTP method as "do_it", so you're not triggering anything. Because there is no such method, Rails actually passes this on as a parameter of the URL. Hence if you click that you should see your url bar now says ?method=do_it at the end.
There are several problems with what you're trying to do. First of all, the link_to helper expects at least two arguments: 1, the text for the link, and 2 the HREF for the link. So, you really need to use:
link_to 'Run it', url
Second, you need to know what URL to pass to get your controller action.
Please be familiar with the following rails convention: When referring to a controller action you can abbreviate it using the form: controller_name#controller_action. e.g. pages#show or articles#index.
Assuming your controller is called ExamplesController, you can manually trigger the seven standard controller actions as follows:
link_to 'examples#index', '/examples'
link_to 'examples#show', '/examples/123' # 123 is the id of a specific example
link_to 'examples#new', '/examples/new'
link_to 'examples#create', '/examples', :method => :post
link_to 'examples#edit', '/examples/123/edit'
link_to 'examples#update', '/examples/123', :method => :put
link_to 'examples#destroy', '/examples/123', :method => :delete
Note that in the above, INDEX, SHOW, NEW, and EDIT are all GET requests. You could specify :method => :get but that is unnecessary
To abstract this away and take care of assigning the ID when required Rails provides path helpers.
So, to repeat the above using the path helpers you could use:
link_to 'examples#index', examples_path
link_to 'examples#show', example_path( #example )
link_to 'examples#new', new_example_path
link_to 'examples#create', examples_path, :method => :post
link_to 'examples#edit', edit_example_path( #example )
link_to 'examples#update', example_path( #example ), :method => :put
link_to 'examples#destroy', example_path( #example ), :method => :delete
Now, you get these path helpers from the router, and they are defined in your routes.rb file. Within that file if you define:
resources :examples
...then you will get all the path_helpers above.
If you are using a normal RESTful controller and you want to add a custom action, then you need to make one decision: does the action operate on the entire set of objects handled by that controller (like index) or just a single specific one (like show). The reason this is important is this tells the router whether the new action you're defining needs to receive a record ID as part of the request.
If you want to act on the entire collection of objects, you define:
resources :examples do
collection do
get 'do_it'
end
end
If you want to act on just a single member of the collection you define:
resources :examples do
member do
get 'do_it'
end
end
Where I wrote 'get' in the examples above you can use any of the four verbs -- GET is normally what you do if you want to show a page, and POST is normally what I'd use if you're submitting a form. You can also write this shorthand like so:
resources :examples do
get 'do_it', :on => :collection
post 'something', :on => :member
end
For more on defining custom controller actions, see the rails guide.
Now that you've defined a route, you should run rake routes in terminal to see the name of the new path helper. Let's assume you added do_it as a collection method, your path helper would be: do_it_examples_path.
Now then, back to your link, if you put:
<%= link_to 'Do it.', do_it_examples_path %>
... then you would trigger the do_it action. When the action is triggered your puts should normally render to the server log (assuming you're running rails s in a terminal window you should see it right after started GET on examples#do_it...).
Now, in the browser you would get a missing template error as a GET request is going to expect to render a view, but that's a subject for another question. Basically, now you should understand what the controller actions are, how you get to them. If you want to learn more about what to do with your controller action, see the guide :)
I hope you understand what's going on now. Feel free to ask questions.
You want to use the Rails logging mechanism:
http://guides.rubyonrails.org/debugging_rails_applications.html#sending-messages
This means that even if you don't launch the server using rails s the output will still go to the right place.

Rails 3 edit_path method not working

sorry if this is a dumb Q, this is my first Rails3 project...
For some reason, this <%= link_to 'edit', edit_geofence_path(geofence) %>
renders as edit (my geofence's id is 2).
And <%= link_to 'delete', {:action=>'destroy', :id=>geofence}, :confirm=>"You sure?", :method=> :delete %>
renders as delete,
which might be fine, but clicking the link generates this in the logs Started GET "/geofence?id=2". So, not DELETE, just GET.
My routes.rb file is just resource :geofence.
On a related note, for some reason the default action for a geofence is "show". So /geofence/ DOES NOT call the index method, it calls the show method. I think that also must be wrong.
I'm done cursing at this app for now, I'm going to take a day to cool off and hopefully get this SIMPLE SCAFFOLD working tomorrow night... Help me, stackoverflow! You're my only hope!
<%= link_to 'delete', {:action=>'destroy', :id=>geofence}, :confirm=>"You sure?", :method=> :delete %>
should be:
<%= link_to 'delete', {:action=>'destroy', :id=>geofence}, :confirm=>"You sure?", :method=> :delete, :remote => true %>
Without :remote => true, the click isn't handled by javascript.
And in your routes.rb file, you should have that defined as:
resources :geofence
Setting it as resource implies that there is only one, and is causing a lot of your weird behavior.
As a side note, to complete ctide answer I would suggest you to use the plural form of your controllers name as a convention. It will sound more natural to put:
resources :geofences
inside your routes.rb file.
Here is a previous StackOverflow question, about using the plural form as a convention for controllers.
When you use resource :geofence in your routes file you are telling your application that there is only one geofence resource, and that it is not a collection. You will get show, update, create, new, but not index - and the id value will not be used because there is only one resource. (The show action here will have the path /geofence
If you use resources :geofences (notice the pluralization) then you've defined a collection of resources, /geofences will now give you the index action and your url helpers will work correctly with the show action rendering /geofences/3.
Hope this helps you understand why the plural form is necessary for this sort of resource :)

Performing AJAX delete operations restfully in rails

How do you perform delete and put operations restfully in rails? I have read the documentation and thought I was doing everything properly, but I can't seem to get it to work.
For example, if I wanted to delete an employee I would create a controller called "EmployeesController" and create a destroy method to perform the delete.
Then I went into the routes.rb file and entered map.resources :employees, which gives you access to the URL helper functions.
In whatever I want to call the Ajax operation from, I should just have a line like:
<%= link_to_remote "Delete", employee_path(#employee), :method => :delete %>
When I click on the link, it is still is sending a POST operation, so it does nothing.
What am I missing or doing wrong?
Try
:url => employee_url(#employee)
IIRC, *_path is a named route generated by the :resource directive which includes the method, thus overwriting your :method => :delete
From my code:
<%= link_to_remote "Delete", :url => post_url(post), :method => :delete %>
Just to add a few extra details: Using :url => employee_url(#employee) helped (from the accepted answer). The other part that was messing me up was the fact that I was expecting an HTTP delete request, but I kept getting POST requests with a parameter "_method" (automatically added by rails) which was set to delete.
So it was calling the proper destroy action, which I proved by adding a couple of debug statements to the controller. Yes, my delete code was wrong in the controller, so it wasn't really deleting when I thought it was.
If your problem is not having AJAX request you have to add proper javascript tags

Resources