Creating an action inside a controller, after it has been generated - ruby-on-rails-3

I am working on a rails app, and have generated a Controller via
rails g controller Pics index upload
but now I would like to add another action
delete
do I do this by manually adding a delete method in the Pics controller?
Or do I need to run another generation. My concern is that by adding manually something may not get included (not sure what it would be, but something under the hood.)
Is this the best way of adding a new action to a generated controller?

If you add manually, just make sure you have the right route on your routes.rb.
Let's say you create your delete action inside your Pics controller.
def delete
# do stuff
end
On your routes.rb, you need to append the route to your resource like this, remembering to analyse if it is a resource that acts upon a member of your resource, or a collection. (More about this you can read on this guide http://guides.rubyonrails.org/routing.html#adding-more-restful-actions).
resource :pics do
collection do
post :delete
end
end
Or
resource :pics do
member do
post :delete
end
end
Remember that all RESTFUL actions are handled by default by the rails router, again, try to read the guide i showed earlier for precise information about the topic. Hope it helps.

Related

Devise: Load a partial instead of showing a notice for non confirmed members

Is there a way to load a view for no confirmed users that login?
Default behaviour is to show a notice: " You have to confirm your account before continuing."
I tried
overrule the sessions#create method of devise checking for current_user.confirmed_at.blank?
in the after_singin_path check for current_user.confirmed_at.blank? and render the view instead
My goal is to render a custom view instead of the notice but cannot hook into the right location. Who knows how to accomplish this? thx!
You can simply copy the code from the devise github and place in your controllers/devise. then change any action or method you want to.
You may also just extend the devise session controller and override any action you want to.
class Abc < Devise::SessionsController
# this just reopens the class.
# Remember classes are never "closed" in ruby!
end
I like the ruby way of solving this, I guess that in your UsersController after a POST request the user will be returned and signed in using the sign_in(Object) helper Devise provides.
Also I suggest using a confirmed boolean instead of timestamp.
Why not check for the value using an if else statement the ruby way:
user.confirmed ? sign_in(user) : render :partial => 'path/partial'
Hope this might help you out

Why Rails Controller Action Method Requires Parameter

It's a brand new project. Here's the exact commands I've run:
rails new MyProject
bundle install
rails generate controller Image
I've added this one route:
root :to => "image#process"
I've added this function to the ImageController (image_controller.rb)
def process
render :nothing => true
end
And finally I've removed the default index.html. When I run the project, it has an error saying process expects 0 parameters, not 1. So I modify the method to tell me what parameter is trying to be sent to process.
def process(arg)
p arg
render :nothing => true
end
The string "process" is printed to the screen. I've done several Rails projects before and never encountered this. Did I miss a step somewhere? Is this something new in Rails 3.0.10? Or maybe caused by Ruby 1.9.2? I think I usually use 1.8.7.
You can not name an action as process, this is an internal method for rails controllers, name it something else.
There's a bunch of other names you can't use for controller actions like render, params, request. Unfortunately there isn't a list of these things.
For future reference, in case you aren't using it, you can view all internal methods and classes here: ruby doc with nav on top right
Helps me when picking names.

Rails 3 - index action not loading by default on controller

Now i have a fresh rails 3 install running over rvm 1.9.2
I generated a controller using the follow instruction:
rails generate controller blog index
The output is
create app/controllers/blog_controller.rb
route get "blog/index"
invoke erb
create app/views/blog
create app/views/blog/index.html.erb
invoke test_unit
create test/functional/blog_controller_test.rb
invoke helper
create app/helpers/blog_helper.rb
invoke test_unit
create test/unit/helpers/blog_helper_test.rb
but in browser when i try to get to http://localhost:3000/blog i get:
No route matches "/blog"
but if i type http://localhost:3000/blog/index
it renders the index view.
doesn't it works like Rails 2? where i get to the index view by default with just putting the controller name on the url ?
thanks.
If you look into routes.rb you'll see
get "/blog/index" => "blog#index"
So just remove it with
get "/blog" => "blog#index"
or you can use resources here.
But only question: why do you use singular form? It is nonsensical to call index to singular noun. You should use or "blog#show" as a resource or "blogs#index" as a resources.
Conventions in Rails is a kind of basement. Don't break them if you can follow them
For rails 3:
match '/blog', :controller => 'blog', :action => 'index'
Rails generate does not generate resources for your controller by default. You specified one action for your controller, 'index', so in your case you end up with this in config/routes.rb:
Blog::Application.routes.draw do
get "blog/index"
The simplest thing to do would be to change this to:
get "blog", :to => 'blog#index'
ian.
This is a guess, based on my experience with Rails 2, but here's what I think is happening:
If you'd generated your controller with the scaffold option (that's still in Rails 3, right?), it would have created a model in addition to your controller, and added the corresponding routes via a call to map.resources (or Rails 3 equivalent) - this last bit is what gives you the /models routes you're expecting.
But since you just generated the controller, no model was created, and thus Rails doesn't put in a map.resources statement in routes.rb - map.resources really only makes sense when there's a model underlying your controller. In fact, I don't think it adds any special routes when you generate a controller; you're getting to your index by one of the default routes: /:controller/:action.
So if you want to get to your index from /blog, you'll have to add the route yourself. Luckily, it should be a one-liner.
Hope this helps!
PS: And if you're paranoid, you'll want to disable those default routes before you go to production - they allow GET requests to trigger actions that change your database (e.g. GET:/blog/destroy), opening you up to Cross-Site Request Forgery attacks.
Add this to your routes.rb file match ':controller(/:action(/:id))(.:format)'
It's better if you add it at the bottom of the routes.rb file.
The problem with this approach is that it will make all your actions available through get request. So be careful with that.
Instead of manual routing you can go to /app/controllers/application_controller.rb and add a blank index method
def index
end
make sure your generated controller extends the application controller, and boom all your generated controllers do what you want
Tested on Rails 3.2.*

Passing controller method attributes in before_filter methods in Rails 3

I'm trying to only allow access to galleries by users who have permission to view them. Galleries have many shared_users through permissions, and vice versa. Galleries also have only one owner. Owners and shared users are both of the User class. This all works fine. The issue that I'm having, however, is with my access filters.
I'm using the following code to see if a user is allowed to see the gallery they are trying to access:
def authenticate_viewers!
if user_signed_in? && current_user.can_view?(#gallery)
return true
end
redirect_to root_url,
:notice => "You must have permission to view this gallery."
return false
end
As you can see, can_view? requires the #gallery that I'm setting up in the show method, but a before_filter won't let you access the attributes set up in the method, since it resolves before the method executes. Using an after_filter works, as long as an unauthorized user doesn't try to view the gallery. If it does, I get a DoubleRender error, since after_filter allows the page to render, then tries to redirect.
I just thought that I could perhaps use params[:id] instead of #gallery, though I haven't tried it yet, and ultimately this may be more efficient (passing an integer instead of an object). In any case, is there a way to make my current code work? or is it in my best interest to switch to using the params (if that's even going to work)?
Wow, okay. It's really helpful just to start writing questions here on SO, because as I do, I typically get a brainstorm of how to solve the problem. Instead of using the #gallery object, I just use a Gallery.find(params[:id]) and everything works like a charm. Thank God I don't have to rewrite all my code.

Rails : Can I use forms from the public/index.html file?

Am currently using Rails 3.0 to develop my app.
How to handle a form in the public/index.html file which I'm planning to use as my Home page.
Usually a view's action buttons gets paired with the corresponding method of its controller.
But how to handle this in case the index file in public directory?
This is possible, so long as the form's action attribute is pointing at an action of a Rails controller. However, it is not the norm in Rails to use a static HTML page to capture data. The norm is to use the MVC architecture of Rails.
I have to ask: Have you read the documentation provided on the Ruby on Rails website? Check out http://edgeguides.rubyonrails.org and read the Getting Started section.
Now, I think you might be using public/index.html because you don't know how to use a controller to serve the root of your website. Here's a quick example of how to use a controller instead of public/index.html:
Create a controller (i.e., home via rails g controller Home index)
Modify routes.rb and add root :to=>"home#index"
Delete public/index.html
The above is actually in the Edge Guides, Getting Stated section. So again, I strongly recommend you read the documentation. It will honestly save you a lot of trouble.