Necessary to include all attributes in view? - ruby-on-rails-3

In a new action in a rails I have this:
#client_order = ClientOrder.where(:client_id => #client.id, :order_date =>
params[:order_date] || Date.today).first_or_initialize
This works perfectly and initializes a #client_order with in that #client_order a filled in client_id
Now I have noticed that in the view I'm obligated to include this line (simple_forms)
<%= f.hidden_field :client_id %>
In order to retrieve that filled in attribute in the create action. Is this normal? What will happen when the user changes that field (through debugging the form)?

It'll get the client ID given in the request.
It's normal if that's how the client is retrieved.
"Authorization" is the part of authentication/authorization that controls whether or not a user has access to a given resource; things like cancan address this.

What does your model for ClientOrder and Client look like? It may be an association problem.
ClientOrder
belongs_to :client
Client
has_many :client_orders

Related

Rails 3 form actions and methods

I have made a resource.
resources :dashboards
I have a partial file which contains a form and I want to use this partial (as the form elements won't change) to update and create. So here is what I have:
Controller
class DashboardsController < ApplicationController
def new
#dashboard = Dashboard.new
end
end
View
/dashboards/new.html.erb
<%= render :partial => "form", :locals => { :dashboard => #dashboard } %>
Partial Form
/dashboards/_form.html.erb
<%= form_for(#dashboard) do |form| %>
.....
<% end %>
Ruby Guide
The Ruby Guide states:
The Article model is directly available to users of the application, so — following the best practices for developing with Rails — you should declare it a resource. When dealing with RESTful resources, calls to form_for can get significantly easier if you rely on record identification. In short, you can just pass the model instance and have Rails figure out model name and the rest. For example:
## Creating a new article
# long-style:
form_for(#article, :url => articles_path)
# same thing, short-style (record identification gets used):
form_for(#article)
## Editing an existing article
# long-style:
form_for(#article, :url => article_path(#article), :html => { :method => "put" })
# short-style:
form_for(#article)
Result
I thought I have followed the Rails Guide correctly. Because I made #dashboard a resource. I could just pass it into the form and have it handle the action, method and the rest. Instead I'm getting this:
<form accept-charset="UTF-8" action="/dashboards" class="new_dashboard" id="new_dashboard_" method="post">
According to the docs. Shouldn't the action of my form now be "/dashboards/new" because we are on the new action? And should it be passing an extra field declaring the method to be put when I use the same code in the /edit action??
My result is always the same no matter what. The form never changes.
What am I doing wrong?
EDIT
Here is my router info from rake routes
GET /dashboards(.:format) dashboards#index
POST /dashboards(.:format) dashboards#create
GET /dashboards/new(.:format) dashboards#new
GET /dashboards/:id/edit(.:format) dashboards#edit
GET /dashboards/:id(.:format) dashboards#show
PUT /dashboards/:id(.:format) dashboards#update
DELETE /dashboards/:id(.:format) dashboards#destroy
You are correct that you should be able to "pass #dashboard into the form and have it handle the action, method and the rest." The issue here is what new is in the context of RESTful actions.
When you declare a set of resources with resources :dashboards, you are creating a set of routes which map requests to controller actions:
GET /dashboards index
GET /dashboards/new new
POST /dashboards create
GET /dashboards/:id show
GET /dashboards/:id/edit edit
PUT /dashboards/:id update
DELETE /dashboards/:id destroy
You can check this if you run rake routes.
The issue here is that the new action is defined as a GET request to the path /dashboards/new, i.e. this is the route for the form itself. The URL in the action attribute of the actual form is something else: this is where the form will post the data to with a POST request, which on the server (rails) side will map to the create controller action.
When you use the form helper with form_for(dashboard), a form is created with a route corresponding to what dashboard is: if it is a new record (i.e. it does not yet exist in the database), then the form action will be create (and point to /dashboards), whereas if it already exists it will point to the actual URL for the record (e.g. /dashboards/123). This is what makes the form helpers so useful.
So, to sum up, /dashboards is the correct URL, not for the new action but for the create action, which the form helper uses because dashboard is a new record. new is the route to the page where the form resides, i.e. /dashboards/new.
Hope that makes sense.
p.s. as a side note, you shouldn't be accessing #dashboard in the partial if you are passing it in as a local (:locals => { :dashboard => #dashboard }). Just use dashboard.

Rails 3 How to access user data from user_id column in belongs_to :user association

I am trying to create an activity feed with the most recent activities from my TrainingSession model.
class User
has_many :training_sessions
end
class TrainingSession
belongs_to :user
end
The problem is that I am trying to access a user's data in the view page (mainly the user's name) by instantiating an object from the TrainingSessions database table, as shown below:
<% #training_sessions.each do |training_session| %>
<%= training_session.user_id %>
The problem is that, although I successfully get the user's id, I cannot call, for example:
training_session.user_id.name
... otherwise I get the NoMethodError shown below:
undefined method `first_name' for 2:Fixnum
so my question is ... how can I access the user's data from the TrainingSession's object?
any help would be much appreciated. Pretty stumped on this one.
The reason that you get a "undefined method `name' for nil:NilClass"-error is that some training sessions do not belong to a user. The solution is to cleanup your database:
DELETE FROM training_sessions WHERE user_id IS NULL
If it is expected behavior to have training sessions that don't belong to a user, you have to check that the user is not nil in your loop:
<% #training_sessions.each do |training_session| %>
<% unless training_session.user.nil? %>
<%= training_session.user.name %>
<% end %>
<% end %>
First of all, you need to rename your model name (TreningSessions) into singular name (TreningSession). That's the convention rails uses. Rename only model, leave has_many without change.
Now the user association,you should call it via user object. user_id is just a attribute that represents field in database and it's value, while user is an association object. Try this:
training_session.user.name
More on ActiveRecord relations
Here is what I ended up doing, creating a local user variable containing the user_id and using that variable with the find method on the user model to instantiate an instance variable #training_session_user in my controller, like the following:
#training_sessions.each do |training_session|
user = training_session.user_id
#training_session_user = User.find(user)
end
then I call this in my view:
#training_session_user.first_name
and it retrieves the name with no errors.
If anyone has a better solution please feel free, but I will mark this as correct for now.

Rails 3.1 associations and counting?

I have two models in my Rails application, Users and Calls.
The model associations are set as follows:
user model
has_many :calls
call model
belongs_to :user
I am trying to call, within the application.html.erb layout, the number of calls that the current user has.
Currently, I am using the following string:
<%= Call.count %>
Which works but it's obviously counting all calls, not just the calls that the current user has.
So I swapped that for the following:
<%= current_user.Call.calls.count %>
I am confused as to how to do this. I need to be able to call the count from anywhere so I can then start working on counting based on the last 30 days etc.
Do this:
current_user.calls.count
You can do the same thing with any User object:
user = User.find(1)
user.calls.count
You then can chain more conditions to do the date-based counts:
user.calls.where("calls.created_at > ?", 30.days.ago).count
You don't really want to be putting database calls within views, you really want to put that into a controller. You'd be looking for something like User.find(current_user.id).calls.count as this will then use the association of which you've set up, or if you want to disregard the model relation you could do Call.where(:user_id => current_user.id).count
So put the below into the relevant controller (in the correct action), and likewise for the view.
Controller
#count = Call.where(:user_id => current_user.id).count
View
<%= #count %>

Create New User with info from another Model - Rails 3.0

I am using Rails 3 and Devise for user authentication. I created a separate scaffold, request_new_user, and I want to have a link on the index page for all of the people who requested an account to go to the new_user_path, with their information sent as well to populate the fields. How would I set the params so I can set the values within the user controller? Or is there a better way to do this? I mainly just want to pass the new user's name and email.
You can generate devise views in your project by: rails generate devise:views .
Send your params in GET request: /signup?email=...&name=...
In registration view you can apply your params, something like:
<%= f.input :email, :value => params[:email] %>
Hope it helps.

REST path for "new from copy"

For certain models, I wish to provide functionality that allows a user to create a new record with default attributes based on copy of an existing record.
I'm wondering what would be the correct restful route for this.
My initial thinking is that it could be a parameter to the new action. I.e. to borrow from the the Rails Guides examples, instead of just:
GET : /photos/new
Also allow:
GET : /photos/new/:id
...where :id is the id of the record to use as a template. The response would be a new/edit form, same as with a plain old new but the values would be pre-filled with data from the existing record. The parameter (or absense of it) could be easily handled by the new controller method.
The alternative seems to be to create a new controller method, for example copy which would also accept an id of an existing record and response with the new form as above. This seems a little 'incorrect' to me, as the record is not actually being copied until the user saves the new record (after probably editig it somewhat).
TIA...
UPDATE: my question is not "how do I do this in rails?", it's "is it RESTful?"
my question is not "how do I do this in rails?", it's "is it RESTful?"
No, it isn't. For that matter, neither is GET /photos/new. Rails seems to be hopelessly mired in the past, where it was considered haute programme for a GET on a URI to return an HTML form which would then POST x-www-form-urlencoded data back to that same URI. The opacity of that POST forces them to invent new verbs-as-URI's like /photos/new, when you could be using PUT instead, or at least POST with the same media type.
The simplest way to make a copy of an HTTP resource RESTfully is:
GET /photos/{id}/ -> [representation of a photo resource]
...make modifications to that representation as desired...
POST /photos/ <- [modified representation]
If you're implementing this for browsers, you should be able to perform those actions via Ajax quite easily, using an HTML page sitting perhaps at /photos/manager.html/ to drive the interaction with the user.
You can try to use nested resources. I'm not exactly sure about structure of you application, but in general using nested photos will look somehow like this:
routes.rb
resources :photos do
resources :photos
end
photos_controller.rb
before_filter :find_parent_photo, :only => [:new, :create]
def create
#photo = Photo.new params[:photo]
if #parent_photo.present?
# fill some #photo fields from #parent_photo
end
#photo.save
respond_with #photo
end
def find_parent_photo
#parent_photo = Photo.find(params[:photo_id]) if params[:photo_id].present?
end
new.html.haml
= form_for [#parent_photo, #photo] do |f|
-# your form code
previously when you wanted to add a link to photo creation you wrote something like that
= link_to "new photo", [:new, :photo]
now if you want to add a link to photo creation based on foto #photo1
= link_to "new photo based on other one", [:new, #photo1, :photo]
You should be able to match a route like so:
match 'photos/new/:photo_id' => 'photos#new
or you could just pass a :photo_id parameter in the url and handle it in the controller:
'/photos/new?photo_id=17'
Example using helper method: new_photo_path(:photo_id => 17)
Edit: I don't know if this conforms to REST
It may be over the top, but you could do something like this:
class PhotoCopiesController < ApplicationController
def new
#photo = Photo.find(params[:photo_id]).dup
end
def create
end
end
and
resources :photo_copies, :only => [:new, :create]
and
= link_to 'Copy', photo_copy_path(:photo_id => #photo.id)