changing route variable for a resource - ruby-on-rails

I just decided that the 'show' action of my 'users' controller should no longer render a page, but rather some json to be used by an ajax call. Edit: I've already implemented this part. My controller just has
def show
render :json => myobject
end
My javascript in the views generate the url to do the AJAX, and all that works fine. As for my question: I'm just looking to take a little shortcut; instead of going through all the places that I link to this action in a view, with something like
<%= link_to "Foobar" user_path(#user) %>
and replacing it with
<a href='javascript:blahblah'>Foobar</a>
I'd like it if user_path instead just spit out my javascript URI. Admittedly, this sounds like a terrible hack, but can it be done?

you can specify the format :
user_path( user, format: :json )
if you want your helper to throw an error, just override it in application_helper.rb :
def user_path( *args, options = {} )
raise MyException
end
... or just use your favorite IDE / shell to find all occurences of the helper.

As a hack, you can go to helpers/application_helper.rb and insert there
def user_path(*args)
"javascript:..."
end
This will do the trick. But I don't recommend it as a long-term solution, only as a quick workaround to check how your new code works, probably.
Besides, if you want to build the link for the right user you'll need to parse all possible combinations of user_path parameters. If you only call it in the user_path(#user) format then it's relatively easy.

You can specify a default format for a route in config/routes.rb:
resources :user, defaults: { format: 'json' }
If you only want to do this for show:
resources :user, only: [:show], defaults: { format: 'json' }

Related

Rails Take all actions in the controllers in area

In my rails application I add an "api" area with controllers
In the route.rb file
I add the area
namespace :api do
#get "dashboard/sales_rate"
end
The controllers Class:
class Api::DashboardController < Api::ApplicationController
before_filter :authenticate_user!
def user_service
render :json => {"user_id" => current_user.id}
end
The Path is:
app/controllers/api/dashboard_controller
My question is if I can that the route take all action
for example /api/dashboard/user_service
and I will not add for each route row on the route.rb page
/api/{controller_under_api_namespace}/{action}
You can do with some meta programming sprinkle!
Api.constants.each |c|
c.action_methods.each do |action|
get [c.controller_name, action].join('/')
end
end
This method limits only to GET request. You can overcome it with RESTful routing.
Api.constants.each |c|
resources c.controller_name.to_sym
end
Hope, that helps. :)
I try add the code on the route.rb file
and I got this error
This is my file
But before trying to fix this part of code, I want to know if it's can change the performance or the calls to those pages?
If it not good for the performance I leave this option.

How do I add different types of GET routes that require parameters in Ruby on Rails

I have a list of users being displayed, you can click on "Show user" or "PDF" to see details of that user in HTML or as a PDF document. The show was automatically created with scaffolding, now I'm trying to add the option to view it as a PDF. The problem is adding a second GET option, if I pass the user along as a parameter, it is assumed to be a POST and I get an error that the POST route does not exist. I am not trying to update the user, just to show it in a different way, basically to add a second "show user" option.
How do I tell it that I want a GET, not a POST? Is there an easier way to do what I am trying to do? Thanks.
Please, create a controller like this:
class ClientsController < ApplicationController
# The user can request to receive this resource as HTML or PDF.
def show
#client = Client.find(params[:id])
respond_to do |format|
format.html
format.pdf { render pdf: generate_pdf(#client) }
end
end
end
Please, update route.rb file, action name with post and get, like below :
match 'action_name', to: 'controller#action', via: 'post'
match 'action_name', to: 'controller#action', via: 'get'
More info please read this link : "http://guides.rubyonrails.org/routing.html"
you haven't posted any code or details, so I am guessing you want something like this:
routes
resources :users
controller
class UsersController < ActionController::Base
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.pdf # handle the pdf response
end
end
end
view file in views/users/show.pdf.prawn
prawn_document() do |pdf|
#user.each {|r| pdf.text r.id} # will print user id of the user
end
The way above example will work is, if something visits the following URLs, they will get html file:
localhost:3000/users/1 #html is the default format in rails
localhost:3000/users/1.html
but if they visit .pdf, they will be served a pdf format.
localhost:3000/users/1.pdf
If the above assumptions are correct, then check prawn or wicked_pdf pdf gem. the above example uses prawn
Checkout this link http://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to. You can add a new MIME type and pass on the :format as pdf in all your rails routes.
Hope this will help.
And for the POST-request check your
config/routes.rb
There shoud be a few routes already, so you can infer the route you need.
In your link you can pass an additional parameter called format for pdf. For e.g.
<%= link_to 'Display in PDF', "/user/pdf", :format => "pdf" %>

Ruby on Rails: Need help updating db attribute in a nested route

Let me preface this by saying, i'm pretty new to rails and programming.
I'm trying to make some links to toggle a boolean attribute on and off. I've essentially succeeded in doing it on a non-nested resource by doing the following:
Route:
resources :my_resource do
get 'toggle_attribute', :on => :member
end
Controller:
def toggle_attribute
#resource = Resource.find(params[:id])
#resource.toggle!(:attribute)
end
View:
<%= link_to "Toggle Resource", toggle_attribute_resource_path(#resource), :remote => true %>
First, like I said above, this works on my non-nested route, however no matter what solution I try to add to the controller I can't get my link to flash a message or re-direct to anything when clicked, you click the button and nothing happens, you have to manually refresh to see the change.
Second, I can't figure out how to get this same sort of thing to work on a route that is nested like so:
Route:
resources :resource_1 do
resources :resource_2
end
Can anyone give me some tips?
Thanks a ton in advance. This stuff has been driving me batty.
By using remote => true, you are telling it to make an ajax call. This means that you need to also add a toggle_attribute.js.erb file in your views folder and in that file use javascript to replace the link element or text with what you want.
Also make sure to respond to js by setting respond_to :html, :js at the top of your controller.
repond_to :html, :js
def toggle_attribute
#resource = Resource.find(params[:id])
#resource.toggle!(:attribute)
end
toggle_attribute.js.erb :
$('#toggler').html("my new html here");
in view:
<%= link_to "Toggle Resource", toggle_attribute_resource_path(#resource), :remote => true, :id => "toggler"%>
Update:
For your nested route try this:
resources :resource_1 do
resources :resource_2 do
member do
get :toggle_attribute
end
end
end
your path would be something like:
toggle_attribute_resource_1_resource_2_path(#resource, #resource2)

Rails: Route to custom controller action

I have a really hard time understanding routes and I hope someone can help me.
Here's my custom controller
class SettingsController < ApplicationController
before_filter :authenticate_user!
def edit
#user = current_user
end
def update
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
end
and I have the file settings/edit.html.erb and my link
<li><%= link_to('Settings', edit_settings_path) %></li>
The route
get "settings/edit"
doesn't work for this, because then I get
undefined local variable or method `edit_settings_path' for #<#<Class:0x00000001814ad8>:0x00000002b40a80>
What route do I have to give this? I can't figure it out. If I put "/settings/edit" instead of a path it messes up as soon as I'm on a other resource page because the resource name is put BEFORE settings/edit
Thx
Following should do:
get 'settings/edit' => 'settings#edit', :as => :edit_settings
# you can change put to post as you see fit
put 'settings/edit' => 'settings#update'
If you use /settings/edit directly in link, you shouldn't have problem with other resource name being prepended in path. However, without the leading slash, i.e. settings/edit it might have that issue.
Reason why edit_settings_path is not working might be because you didn't declare a named route. You have to use :as option to define by which method you will be generating this path/url.
If you want to explicitly define the route, you would use something like
get 'settings/edit' => 'settings#edit', :as => edit_settings
This statement defines that when a GET request is received for setting/edit, call the SettingsController#edit method, and that views can reference this link using 'edit_settings_path'.
Take some time to read the Rails guide on routing. It explains routing better than any other reference out there.
Also keep in mind the rake routes task, that lists the details of all the routes defined in your application.

Rails redirect_to post method?

redirect_to :controller=>'groups',:action=>'invite'
but I got error because redirect_to send GET method I want to change this method to 'POST' there is no :method option in redirect_to what will I do ? Can I do this without redirect_to.
Edit:
I have this in groups/invite.html.erb
<%= link_to "Send invite", group_members_path(:group_member=>{:user_id=>friendship.friend.id, :group_id=>#group.id,:sender_id=>current_user.id,:status=>"requested"}), :method => :post %>
This link call create action in group_members controller,and after create action performed I want to show groups/invite.html.erb with group_id(I mean after click 'send invite' group_members will be created and then the current page will be shown) like this:
redirect_to :controller=>'groups',:action=>'invite',:group_id=>#group_member.group_id
After redirect_to request this with GET method, it calls show action in group and take invite as id and give this error
Couldn't find Group with ID=invite
My invite action in group
def invite
#friendships = current_user.friendships.find(:all,:conditions=>"status='accepted'")
#requested_friendships=current_user.requested_friendships.find(:all,:conditions=>"status='accepted'")
#group=Group.find(params[:group_id])
end
The solution is I have to redirect this with POST method but I couldn't find a way.
Ugly solution: I solved this problem which I don't prefer. I still wait if you have solution in fair way.
My solution is add route for invite to get rid of 'Couldn't find Group with ID=invite' error.
in routes.rb
map.connect "/invite",:controller=>'groups',:action=>'invite'
in create action
redirect_to "/invite?group_id=#{#group_member.group_id}"
I call this solution in may language 'amele yontemi' in english 'manual worker method' (I think).
The answer is that you cannot do a POST using a redirect_to.
This is because what redirect_to does is just send an HTTP 30x redirect header to the browser which in turn GETs the destination URL, and browsers do only GETs on redirects
It sounds like you are getting tripped up by how Rails routing works. This code:
redirect_to :controller=>'groups',:action=>'invite',:group_id=>#group_member.group_id
creates a URL that looks something like /groups/invite?group_id=1.
Without the mapping in your routes.rb, the Rails router maps this to the show action, not invite. The invite part of the URL is mapped to params[:id] and when it tries to find that record in the database, it fails and you get the message you found.
If you are using RESTful routes, you already have a map.resources line that looks like this:
map.resources :groups
You need to add a custom action for invite:
map.resources :groups, :member => { :invite => :get }
Then change your reference to params[:group_id] in the #invite method to use just params[:id].
I found a semi-workaround that I needed to make this happen in Rails 3. I made a route that would call the method in that controller that requires a post call. A line in "route.rb", such as:
match '/create', :to => "content#create"
It's probably ugly but desperate times call for desperate measures. Just thought I'd share.
The idea is to make a 'redirect' while under the hood you generate a form with method :post.
I was facing the same problem and extracted the solution into the gem repost, so it is doing all that work for you, so no need to create a separate view with the form, just use the provided by gem function redirect_post() on your controller.
class MyController < ActionController::Base
...
def some_action
redirect_post('url', params: {}, options: {})
end
...
end
Should be available on rubygems.

Resources