Spyros
Spyros

Reputation: 48706

How to Handle These Resources

i'm having a situation where i have 10 resources(controllers) that correspond to 10 database entries. In particular, it is about buildings. There is a town_center controller, a sawmill controller and more.

I did not want to create a buildings_controller and handle everything there, since each building behaves very differently.

But i have a question on routes and how to handle a particular situation. I would ideally want to have urls like :

/town_center/view
/sawmill/view

This is fine, but i have a fundamental problem. There is no easy way to get the town_center id number from the url. I would of course need this information, in order to get model information about the particular building. Now, one could argue that i can just use this :

/town_center/view/1
/sawmill/view/2

Which seems fine, but poses another fundamental problem, and that is, that i have to specify the id, when i redirect from another controller. Say that i want to redirect to the town_center controller. I would need to do :

redirect_to town_center_url(1)

Which i really don't like, because the id can change anytime in my database and is generally a bad programming practice for sure, very prone to errors.

How would you handle this ? Am i missing a simpler way ?

EDIT :

EXAMPLE ROUTES WITH ID NEEDED

  scope :path => '/town_center', :controller => :town_center do
    get '/view/:id' => :view, :as => 'town_center'
  end

  scope :path => '/sawmill', :controller => :sawmill do
    get '/view/:id' => :view, :as => 'sawmill'
  end

EXAMPLE OF USAGE

Starting from /overview, we see a list of building links like :

/town_center/view/1
/sawmill/view/2

If one clicks on the first, the view action with an :id of 1 is executed. Fine till now. But say that on this view template, there is an action like send_message. Now, this action is like :

def send_message
   send_the_message_blah_blah
   redirect_to sawmill_url(2)
end

Now, i guess the problem is clear. In order to redirect to the sawmill viewpath, i need to know its id, which means that i would have to make an extra query, for no real reason, like :

def send_message
   send_the_message_blah_blah
   redirect_to sawmill_url(Building.where(:name=>'sawmill').first)
end 

And if i don't include the :id in the url at all, then my view action is just not aware of what building it should refer to.

Upvotes: 1

Views: 75

Answers (3)

Azolo
Azolo

Reputation: 4383

So if it were me, I would change my routes up and put a before_filter in each controller that does the query for you.

So like each one of your routes would look something like this instead.

scope :path => '/sawmill', :controller => :sawmill do
  get '/view' => :view, :as => 'sawmill'
end

then in your SawmillController you would add the before filter to get the sawmill from the database.

class SawmillController < ApplicationController
  before_filter :get_sawmill
  ...
private
  def get_sawmill
    @sawmill = Building.where(:name=>'sawmill').first
  end
end

That way anytime someone takes action on a controller, they won't even know that there is a database behind it. The controller does all the legwork AFTER the request is made.

This way you cut the :id out of your url and _url methods completely. Meaning just sawmill_url instead of sawmill_url(1), and your url will be /sawmill/view. Nice and clean!

Upvotes: 1

KobeJohn
KobeJohn

Reputation: 7545

This makes me think either you don't understand the way rails wants you to do things or that your situation has some special considerations that we are still not aware of:

(edit: looking at your answer history, it seems you know much more about rails than I do so I'm guessing it's the second. please skip to the bottom of this question for my request for you)

redirect_to town_center_url(1) Which i really don't like, because the id can change anytime in my database and is generally a bad programming practice for sure, very prone to errors.

The only solution I know for accessing a resource without some kind of id is through some other contextual information. For example with the devise authentication system, you don't ever use your id anywhere. If you are authenticated, then the server knows who you are and doesn't want to throw your id around unnecessarily in urls or whatever. So similarly if you have someone logged in, you can identify their resources through their session.

example controller (should probably be in a town model actually):

@tc = current_user.town_center
@b = current_user.barracks

view

<%= link_to 'Town Center', @tc %> <%# which still is using some identifier %>

Or if you had a "location" then you could identify the lone town_center through the location similar to above (but now you need the location identifier).

Basically, unless you have some special context, you will need an identifier somewhere.

If that doesn't help, I think you should walk us through one example of how you would like for things to work from zero (user comes to your page. what do they see?) to .... somehow opening a building resource (when does the building originally become available?) to... doing some action with that building.

Upvotes: 0

nodrog
nodrog

Reputation: 3532

match '/town_center/view/:id' => 'town_center#view'

if you have a view action in your controller, but why are you fighting the convention. just have:

resources :town_center

you would call town_center(instance_of_a_town_center) which would give you the path

/town_center/1

why do you need the view? its just the get method for an instance of a town_center in the town_center controller.

hope this helps

Upvotes: 0

Related Questions