how does scaffold works on ruby? how are the params defined? - ruby-on-rails-3

I am using scaffold on ruby on rails, and its great and all, makes everything simpler, but I dont understand one thing and the books or the web dont have a clear solution.
For exmaple, I use scaffold and I create table user and I can make /user/1 and I will see the user with the ID 1 , and if i make /user/edit/1 I will edit user with ID number 1, but on the controller the code its like this
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
According the MVC Ive worked, the controller is the first in respond, so, in some way I should be able to indicate to use the show method, but how? I dont have anything else added on my routes file. any idea??

The default routes are "HTTP Verb: GET, Path: /photos/:id, Action: show, Used For: display a specific photo". See the documentation.

Scaffold add resource :users in your routes.rb file `. This actually enables all RESTfull routes. You can see the default routes in this table (bellow). This is what is defined as convention over configuration, and it is because of this that rails is magical. Once you master a few conventions, your will be able to do more with less.
table http://i.imm.io/150CI.png
By the way, this is a really nice site to use if you are planning to learn Rails. I'm not aware of a better source, even books.

Related

Accessing Custom Parameters when using Devise and Rails 4

I am learning rails using the teamtreehouse tutorial. The tutorial uses 3.1 but I am trying to learn 4.0, and as a result I have run into a difficulty presumably because rails 4 forces of the use of strong parameters. I have two models, a users model and a statuses model. I have used devise to create authentication for users, and have included new parameters. They are :first_name, :last_name, and :profile_name. I have created a relationship between users and statuses.
Currently the user sign-up with the new parameters is working; i can access them using for instance current_user.last_name. However, I want to show the profile_name of the user that created the post on the statuses index view(each user does not yet have a separate page). I want to do this using
status.user.profile_name
However it just shows up blank. If I do
status.user.email(which is a preconfigured devise parameter), it shows up no problem. I am guessing I have to whitelist these parameters in some controller but I don't know where or how.
Thanks
I think, here you will find your answer: https://github.com/plataformatec/devise/tree/rails4#strong-parameters
Based on above link, I think you should insert something like this in your ApplicationController:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:user) { |u| u.permit(:profile_name) }
end
end
And I already suggested in a previous question...
Strong parameters with Rails and Devise
...that you can create your own controller which could extend devise own controller. There is a gist for that:
https://gist.github.com/bluemont/e304e65e7e15d77d3cb9
A little bit more details in Devise doc: https://github.com/plataformatec/devise/tree/rails4#configuring-controllers

Rails 3: How to get a custom restful member route without ID

I'm working on a project where users can upload videos through a simple form and additionally by FTP to a certain directory and then simply choose the file from the FTP directory instead of uploading it through the form.
I got the following, pretty standard setup for a videos_controller:
# routes.rb
resources :videos
# new.html.rb
form_for(#video) do |f|
...
end
The restful actions in the controller are all working and just standard behaviour. The upload works, that's not the problem. The problem is if I do the following:
# routes.rb
resources :videos do
member do
post :from_ftp
end
end
# new.html.rb
form_for(#video, :url => from_ftp_video_url) do |f|
...
end
I get the error: No route matches {:action=>"from_ftp", :controller=>"videos"}, because the generated route looks like this:
from_ftp_video POST /videos/:id/from_ftp(.:format) videos#from_ftp
which seems right, since it's a member route. But I don't need the :id part of the URL, since I'm creating a new Video object, not through a form but simply by using the file from the FTP directory... So it basically is another create action, that's why I would like to do it as a POST request...
So how do I tackle this the best way?
Although the selected answer is correct for Vapire's situation, it doesn't necessarily answer the title question. If you came here looking for how to get member actions without an ID because you don't need an ID, the answer is a little different.
Say you implemented authentication that sets current_user. You let users edit their own profile only. In that case users/:id/edit doesn't make sense because :id is dictated by the current_user method. In this case /users/edit makes more sense.
You can change your routes.rb file to create member actions without an id in the path.
...instead of this...
resources :user
...use this (note the plurality of resource)...
resource :user
The way to understand member and collection routes is this:
Member routes do something to an object that you have.
Collection routes do something to the set of all objects.
So when we consider what the create route would be, it's a collection route, because it's adding a new object to the collection!
So your from_ftp method should also be a collection route, because it's adding to the collection.
Also, you might want to consider if you can accommodate the FTP functionality within your existing create method - it might be neater.

How do I utilize user input without putting info into a Model?

This is an incredibly newbish question, but I can't seem to find the answer.
I'm building an app that utilizes external APIs heavily, and I'm fairly new to Rails, so it's still a little rough to get around. I can't, for the life of me, figure out how to accept user input and execute a function in my app without writing to a model.
For example, I just want to let a user type in a Twitter username and have it display on the page. I know how to make a form to cache the search in a model, but I can't figure out how to just... make a function happen on a page. I've been breaking my brains on this for several days now.
Please help? :/
You don't need a model to use Rails, but if you don't need ActiveRecord at all, you might benefit from a lighter framework like Sinatra. That doesn't answer your question, but it's worth thinking about if you really have no database requirement for your application.
It sounds like you're just trying to access non-resourceful user input, which is accessible in the controller via the params hash. So, assuming you have set up a valid route for the form action, you use your controller to extract GET or POST parameters.
For example:
# You define a non-resourceful route in routes.rb for your form action.
get 'twitternames/show'
# Form action directs user to GET the following route after filling in the form.
http://example.com/twitternames/show?user=foo
# The controller action extracts the data.
def show
#user = params[:user]
# render the view unless you tell rails to do something else
end
# show.html.erb
<%= #user %>
Creating the right route is the key. Once you've defined a route that can break a URL into the proper segments, the rest will fall into place.

Use of "new do" in Rails 3 Routes

I'm working with a Rails 3 Routes file and the resource mapping looks like this:
resources :projects do
new do
post :add_test_phase
post :add_client
post :refresh_form
end
I've read the Routes Guide for Rails 3 but find no mention of this. I know what "member" or "collection" add but am stumped by this new tag. Does it mean perform the mentioned posts when a new project is created?
It works just like the post do block does. It's just for creating a bunch of new routes. Your above example would give you add_test_phase_new_project_path mapped to projects#add_test_phase, add_client_new_project_path mapped to projects#add_client, refresh_form_new_project_path mapped to projects#refresh_form. The urls would be /projects/new/add_test_phase, /projects/new/add_client and /projects/new/refresh_form. Although, honestly, I don't really see a good use case for this.

Non-plugin role management in Rails

I've used CanCan before and it's great, but sometimes I don't need such customizable role management. Sometimes I just need to distinguish between an admin and everyone else. So, I usually just write an :authenticate_admin! method for the controllers and methods I need to protect.
What I've found a little more complicated is ensuring that users can only manage resources they own. Say, I user can create posts, I don't want them to be able to update or destroy a post they didn't create. So, I'm curious about how others have gone about handling this in the most DRY way possible.
Here's what I've done, off the top of my head:
In the application controller:
def user_can?(resource_user_id, current_user_id)
return true if current_user.is_admin
return true if resource_user_id == current_user_id
end
Then, in the controller in question, I do something like
before_filter :can_manage_project?, :except => [:new, :create]
and
protected
def can_manage_project?
#project = Project.find(params[:id])
return true if user_can?(#project.user_id, current_user.id)
redirect_to user_path(current_user), :flash => {:error => "Sorry, you're not allowed to do that."}
end
Seems like a lot of code for a relatively simply task. How have you gone about handling this task? I'm sure there's a more elegant solution -- short of using a gem or plugin.
My first thought would be to abstract out a tiny bit and mix in an is_manageable? method into models via a acts_as_user_manageable-type doodad. Resource controllers would get a manageable_by_current_user? filter (I'm not sure how I'd do that automagically yet). is_manageable? could encapsulate arbitrary rules, so it would be able to handle things like admin flags etc.
I'd have to play a bit to see what implementation I liked the most, but a solution like this seems pretty reasonable, and probably something that a lot of people would dig for projects that don't need the level of control the canonical solutions provide.