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

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)

Related

changing route variable for a resource

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' }

Rails: link_to calls custom method in controller

I am looking to use link_to to call a method in my controller. However, for some odd reason the route looks for the show method.
In my view:
<% #beverages.each do |beverage| %>
..
<%= link_to 'Archive', beverages_archive_path(:id => beverage.id) %>
..
<% end %>
In my config/routes.rb
match 'beverages/archive' => 'beverages#archive'
In my beverages_controller.rb
def archive
beverage = Beverage.find(params[:id])
respond_to do |format|
# format.html # show.html.erb
format.json { render json: beverage }
end
# beverage.update_attribute('archive', true)
end
When I click on the archive link in the view, the URL does change to: http://localhost:3000/beverages/archive?id=11, however I get the following error.
The error I get:
ActiveRecord::RecordNotFound (Couldn't find Beverage with id=archive):
app/controllers/beverages_controller.rb:46:in `show'
Any idea on what I am doing wrong? Your help is much appreciated!
PS. I also looked at Rails 3 link_to delete destory method calls show method?
but nothing seemed to work.
Have you tried this in your routes?
match 'beverages/:id/archive' => 'beverages#archive', as: :beverages_archive
This will create the beverages_archive_path method for you. Also, as you are looking for a specific beverage, use :id inside the route so that it knows where to take the id parameter from.
Apart from that, you can always tell a link specifically which controller and action to link to by doing:
link_to "Label", :controller => :my_controller, :action => :index
Taken from here: Ruby on rails 3 link_to controller and action
Use the other notation (not match) instead.
resources :beverages do
collection do
get :archive
end
end
Try this one out and let me know if something went wrong.
There's not quite enough information here to know why beverages_archive_path works in your app -- one problem is that your routes file does not define a name for your beverages#archive route. What you want is something like:
match 'beverages/archive' => 'beverages#archive', :as => :beverages_archive
or better yet use resourceful routing conventions like so:
resources :beverages do
collection do
get :archive
end
end
What's happening is that you have a beverages#show route that matches /beverages/:id, and this is what /beverages/archive matches (with :id => 'archive').

Active Admin Custom Action Item Resource Name

Don't know why I can't seem to figure this out since it seems like it should be so simple, but basically, I'm trying to create a link to an action (I want "Publish" to appear next to show, edit, delete) for each of a resource in Active Admin.
I used the code they suggest on their wiki:
action_item do
link_to "button label", action_path(post)
end
Problem is, I get an error because rails doesn't know what "post" is. It's nil. The version of the Wiki on Github has the same code, except they use "resource" instead of post. I wasn't sure if that was them implying that I would use my own resource name there, or if you're supposed to actually use the variable "resource". I tried the latter case and got a "Couldn't find without an ID" error.
So the question is, where do I set the variable name? What are they using as their iterator?
I used to use this:
action_item only: :show do |resource|
link_to('New Post', new_resource_path(resource))
end
UPDATE
action_item only: :show do
link_to('New Post', new_resource_path)
end
Thanks Alter Lagos
I have accomplished this with a very similar piece of code, see:
Inside my: app/admin/posts.rb
member_action :publish, method: 'get' do
post = Post.find(params[:id])
post.publish!
redirect_to admin_post_path(post), notice: 'Post published!'
end
In my case, I want the link buttons available only in the show action.
action_item :only => :show do
if post.status == 'pending'
link_to 'Publish', publish_admin_post_path(post)
elsif post.status == 'published'
link_to 'Expire', expire_admin_post_path(post)
else
end
end
Hope this helps you!
In ActiveAdmin you have to use resource to reference an object that you're working with.
When you use resource in an action like index, you will probably get an error as ActiveAdmin is not working with one. To prevent this, specify the actions you want the button to appear in.
To specify an action, give the argument only with an array of the actions you want the button to appear in. For example:
action_item :only => [:show, :edit] do
...
end

How do you use a Rails 3 gem method to update a database model?

I am using the Thumb_Up gem for ruby on rails.
https://github.com/brady8/thumbs_up
I want users to be able to vote on posts.
However, I am unable to figure out how I can allow a user to click a button next to each post and add a vote to the database.
I can get this to happen in the rails console through doing the following:
u=User.first
m=Micropost.first
u.vote_for(m)
However, how can I get this to happen when a button is clicked in view. I am assuming I would have to use ajax, but how would I know the url I need to post to to make this action occur?
Any help would be greatly appreciated.
Update:
Thanks so much for the help! I am still having a problem with the code below.
Here is my routes.rb
resources :microposts do
post :vote, :on => :member
end
View:
<%= link_to('vote for this post!', vote_micropost_path(#micropost), :method => :post) %>
Controller:
def vote
#micropost = Micropost.find(params[:id])
current_user.vote_for #micropost
# This assumes you'll only call it via AJAX.
# If your ajax call doesn't return "ok", then you know something went wrong
render :text => 'ok', :layout => false
end
However, I'm still getting this error:
No route matches {:controller=>"microposts", :id=>#, :action=>"vote"}
Would anyone know why the routes aren't matching correctly?
I am assuming Rails 3. Rails 2's routes would look a little different.
First you would need to define a route in your config/routes.rb file. You could do this many ways. If you already have a route for microposts, you could simply add a "vote" action:
resources :microposts do
post :vote, :on => :member
end
(For clarity, the "post" above refers to the HTTP POST method and has nothing to do with your Micropost class.) If you use that route, you would then need to create a "vote" method in your Microposts controller to catch it. Something like
def vote
#post = Micropost.find(params[:id])
current_user.vote_for #post
# This assumes you'll only call it via AJAX.
# If your ajax call doesn't return "ok", then you know something went wrong
render :text => 'ok', :layout => false
end
Then in your view's AJAX POST call (assuming the example route I gave), you would get the url with:
vote_micropost_path(#micropost)
It would look like /microposts/56/vote

How to add action 'current_user' to a restful 'user'?

I have a model 'User', it's a restful resource, and has the default methods like 'index, show, new, create' and others.
Now, I want to define a new action 'current_user', to show the information of current logged-in user, which is different from 'show'.
When I use:
link_to current_user.name, :controller=>'users', :action=>'current_user'
The generated url is http://localhost:3000/users/current_user, and error message is:
Couldn't find User with ID=current_user
Shall I have to modify the routes.rb? What should I do?
I have searched for some articles, and still have no idea.
Add
map.resources :users, :collection => {:current => :get}
Then, I use:
link_to 'current', current_users_path()
The generated url is:
http://localhost:3000/users/current
Now, everything is OK. Is this the best solution?
See my comment on the other answer for an explanation
map.current_user "users/current", :controller => :users, :action => :current
View:
link_to 'current', current_user_path
I would not add a new action for this. I would check the id passed to the show method.
class UsersController
def show
return show_current_user if params[:id] == "current"
# regular show code
end
private
def show_current_user
end
end
In the view use :current as the user id while generating path.
user_path(:current)

Resources