Associated models without nested routes - ruby-on-rails

I have two models:
class GarageOwner < ActiveRecord::Base
has_many :garages, dependent: :destroy
end
class Garage < ActiveRecord::Base
belongs_to :garage_owner
end
A Garage should never exist without a garage owner. So in the new action of the GaragesController I need the corresponding garage owner. I do not want to use nested routes so I do not have the garage owners id as a parameter. But how do I get him then?
Update for some clarification
Garages are created by a third model (Admin). So I can not access the garage owner through the current user.
I build my routes using resources:
garage_owners GET /garage_owners(.:format) garage_owners#index
POST /garage_owners(.:format) garage_owners#create
new_garage_owner GET /garage_owners/new(.:format) garage_owners#new
edit_garage_owner GET /garage_owners/:id/edit(.:format) garage_owners#edit
garage_owner GET /garage_owners/:id(.:format) garage_owners#show
PUT /garage_owners/:id(.:format) garage_owners#update
DELETE /garage_owners/:id(.:format) garage_owners#destroy
garages GET /garages(.:format) garages#index
POST /garages(.:format) garages#create
new_garage GET /garages/new(.:format) garages#new
edit_garage GET /garages/:id/edit(.:format) garages#edit
garage GET /garages/:id(.:format) garages#show
PUT /garages/:id(.:format) garages#update
DELETE /garages/:id(.:format) garages#destroy

The solution to not using nested routes is to insert the garage_owner_id as a hidden field in your new garage form. But, you've given no indication in your question of how the new garage form is meant to know about which garage_owner it should associate with so I can't give you a specific example.

Perhaps I'm not getting your question, but I think you'd have to either pick up the garage owner from your session (e.g. logged in user), or something derived from a value in your session or as a value submitted with the form used for the new operation, in which case it would be a parameter.

You could approach this a couple different ways:
If the GarageOwer requires a login, you could grab the ID of the GarageOwer user from the cookie stored at login.
Create a custom route match "/Garages/new/:owner_id" => "garages#new", there after in your controller access the owner's id via params[:owner_id].
Add owner_id as a hidden attributed to the form on the "garages/new" page.

I found an appropriate solution which is still restful I think. I just created multiple routes for garages:
resources :garage_owners do
resources :garages, except: :index
end
resources :garages, only: [:index, :show]
Normal users should not access the other actions.

Related

Rails Route for Adding child to parent

Been working in another language for a few months and trying to get back into Rails.
If I have a model House, and a model Door, so that Door belongs_to House and House has_many Doors.
If I want to add a door to the house, do I use the route:
add_door_path
or is it
add_door_path(#house)
And if so how do I embed the house_id in to it? Or do I need to create a new route for that? Is it part of the standard resources or is this entirely custom?
if you have
# routes.rb
resources :house do
resources :doors
end
then you would have house_doors_path(#house)
That is because in your routes you have specified that doors is nested inside the house. You would need the parameter inside because the path requires a house id.
To check for the routes, go here http://localhost:3000/rails/info/routes.
If on the other hand, if you have
# routes.rb
post '/door/' => 'doors#create', as: :add_door
the new door would not know which house it belongs to. so you can add
post '/house/:id/door ... which you also need a parameter of house so your syntax would be add_door_path(#house)
I hope that answers your question.

Rails nested resources, how do I create two new resources when I need the other's id in the GET request?

Pretty much as the title suggest. I have two models, routes like this:
resources :users do
resources :books
end
- which gives me exactly the kind of urls I'm looking for. The problem is that I need to have a logic where a not logged in user can go in and click "create book", and in the new-page chose to click "new user" or "I have an account", which via javascript loads a form for a new user with all its params, or loads a form with only email and password. How do I create this route to work? With these routes it seems I get the path /users/:user_id/books/new, but then I need the user's ID, which I don't have.
Any Ideas?
By the way. User has_many :books, Book belongs_to :user.
Just add the route without the user id:
# with user_id
resources :users do
resources :books
end
# without user_id
resources :books
It looks dangerous btw to have a user id in the URL. That means that anyone can access the the books of any user, just by changing the URL. The ID of the current user should not appear in your routes at all, but should always use cookies or sessions.

handling one-to-one user relations with controllers

I've been wondering if there is any better way to handle one-to-one relations with Rails.
I have a User model, which has_one Subscription. When the user is logged in, I get the subscription by retreiving current_user.subscription, so that finding subscriptions by id in URL is unncessary.
Right now, when user wants to update his subscription, he gets the url:
/subscription/3/?plan_id=2
But the subscription 3 is unncessary, and the other thing is I don't want to be showing the number of subscriptions (ids) to the user.
Whats would be a better solution for this? Would you guys bother with that?
Thanks
You could use resource :subscriptions (not resources). As described here (link)
the difference is, that resource doesn't create an index route (only if you say explicitly that you want one) and doesn't need IDs in the url
Quote from the linked answer:
At a high level, the intent of resource is to declare that only one of
these resources will ever exist. For example:
resource :profile, :only => [:edit, :update] As a user, I should only
be able to update my own profile. I should never be able to edit other
users' profiles, so there's no need for a URL scheme like
/users/1/profile/edit. Instead, I use /profile/edit, and the
controller knows to use the current user's ID rather than the ID
passed in the URL (since there is none).
That's why you don't get an index action with resource: there's only one resource, so > there's no sense in "listing" them.
I guess You have something like this defined in Your routes
resources :subscriptions
What You want is a collection level custom action which is defined like this:
resources :subscriptions do
get 'new_plan', on: :collection
end
Now You will need to add an action in You controller of the same name. And the link to get there will be: /subscription/new_plan?plan_id=2

rails wrong association has_many link

Trying to set up very basic association between Customer and Contact model.
Customer has_many :contacts
Contact belongs_to :customer
User has_many :customers
Routes
resources :customers do
resources :contacts
end
I don't want /contacts to be accessible
When I add in my views
new_customer_contacts_path
I have an error. If I have
new_customer_contact_path(contact)
it works however link to contact#show is wrong
--> it directs to customers/7/contact/2 where it should be customers/2/contact/7
Any idea?
new_customer_contact_path(contact)
This is wrong. You should pass customer to it instead of contact.
If you want to show the contact of a customer, you should use customer_contact_path(customer, contact).
For reference, go to http://guides.rubyonrails.org/routing.html and search 'Creating Paths and URLs From Objects'
You gotta tell the customer whose contact belongs_to!
Like the following:
# Customer.first and Contact.first can be exchanged to instances
# of Customer or Contact!
new_customer_contacts_path(Customer.first)
edit_customer_contact_path(Customer.first, Contact.first)
customer_contacts_path(Customer.first)
With nested routes you need to pass the objects (or at least their ids) in the order they are listed in the route. In the case of 'new' you only need to pass the parent object id as there is no id yet for the new nested object.
new_customer_contact_path(customer)

Rails: How to treat some fields of model info independently? Eg. Account vs. Profile information

I have a User model with the usual information (login, email, name, location, etc). However, when users decide to edit their information, I'd like to separate the fields to be edited according to the appropriate concerns.
For example, I'd like to have Name, Bio and Location to be edited on a Profile page or tab, and login, email and password to be edited on an Account page or tab.
What are the best practices, and the safest way, to accomplish that? Should I have two separate model/resources: User and UserProfile? Or can I just create something like a profile method in the UserController, with a custom form with only the specific profile fields, and link to it in the user page? I'm really confused on how to go about this.
Thanks in advance for any ideas you might have.
I think it depends on the rest of your Application. It sounds like in your case it's good to be modular. If you want users to be able to see the profile of other users, it's an advantage to have a separate model for the Profile and like it with a has_one relationship. I'd just call the class Profile so it can be accessed through user.profile in your controllers and views.
Models:
class User < ActiveRecord::Base
has_one :profile, :dependent => :destroy
end
class Profile < ActiveRecord::Base
belongs_to :user
end
If all your users have both profile and account fields then I wouldn't put it in seperate models. It will only add unnecesary complexiety to your forms and add may add some sql queries.
I don't see here any security problems. In case of editing, both actions (edit account and profile) should be protected the same way - so only owner user should be able to edit both of them. If he want to "hack" it and edit also his login when he edits his first name then it is his problem. It won't cause any problem since he is allowed to edit both fields.
According to views that are viewable for other people: just don't display there any fields that belongs to account part.
How to seperate it? For me the cleanest way is to add this kind of routes:
map.resources :accounts
map.resources :profiles
And use paths like /accounts/34/edit to edit account part and /profiles/34/edit to edit profile part.
In this case you will need a seperate controller for both routes: accounts_controller.rb and profiles_controller.rb. If they share a lot of similar methods and behavior, you can add it in users_controller.rb and in profiles and accounts controllers inherit from it.
You can also do it with one controller:
map.resources :accounts, :controller => 'users'
map.resources :profiles, :controller => 'users'
But I don't know how to pass some additional value with routes created with resources. When you use connect you can pass it with :defaults => {:foo => 'bar'} and then it will be availble in controller as params[:foo] but it doesn't seem to work with resources. So how can you distinguish between accounts and profiles? You can read it from current url (here is example). And then in controller you can render different views according to requested resource.
I would be inclined to cut along the grain here. It's going to be easier to map a model to a form. So if you have information that is accessed within different forms in your UI, I would create a model for each.
That said, at a certain point in my systems I tend to pull the profile information out of the base User class, so the User becomes solely for authentication.

Resources