0

I'm using the gem Ancestry, and trying to build my routes to show the hierarchy between parents and children.

Location.rb

def to_param
  if self.ancestors?
    get_location_slug(parent_id) + "/" + "#{slug}"
  else
    "#{slug}"
  end
end

def get_location_slug(location_id)
  location = Location.find(location_id)
  "#{location.slug}"
end

This works 99% perfectly, and is showing my routes cleanly - but it is showing "%2F" instead of a "/" in my route with a parent:

localhost:3000/locations/location-1 (perfect)
localhost:3000/locations/location-1%2Flocation-2 (not quite perfect)

Routes.rb (sharing just in case)

match 'locations/:id' => 'locations#show', :as => :location, :via => :get
match 'locations/:parent_id/:id' => 'locations#show', as: :location_child, via: :get

Bonus question: This currently covers root Locations and child Locations. How could I extend this to cover grandchild Locations and great grandchild Locations? Thanks in advance!

Kobius
  • 674
  • 7
  • 28
  • 2
    `match 'locations/:id/:id'` I'm surprised that's even accepted by the parser. I don't think you're setting up your routes right. – Josh Brody Jul 09 '18 at 03:44
  • @JoshBrody I think you're right, it looks weird. I'm assuming I should replace the first :id with :parent_id, but I'm not sure what to do if there's another level. For example, would you know if :grandparent_id work? – Kobius Jul 09 '18 at 04:42
  • 2
    Your routes should be [RESTful](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) – Mark Merritt Jul 09 '18 at 04:49
  • You need to go through http://guides.rubyonrails.org/routing.html one more time. You will figure out how nested routes are created. – Jagdeep Singh Jul 09 '18 at 07:27
  • Have you tried declaring your route as `/.../*slug` instead? Rails tries to *aggressively* parameterize everything so that no matter what you put in your identifier it will work properly in a URL and `/` is a reserved character. – tadman Jul 09 '18 at 17:24
  • Another thing to note is `"#{x}"` should almost always be just `x`, as the quotes and interpolation do nothing other than make a mess of your code. In rare circumstances where you need explicit string conversion the best approach is `x.to_s` to make it clear what your intent is. – tadman Jul 09 '18 at 17:25

1 Answers1

1

Just wanted to share my solution, hopefully helps someone.

Firstly, I cleaned up the method in my model:

def to_param
  slug
end

Then, tweaked my routes:

get 'locations/:id', to: 'locations#show', as: :location
get 'locations/:parent_id/:id', to: 'locations#show_child', as: :location_child

Then, I created a new method in my Application helper to generate these URLs for locations with/without a parent:

def get_full_location_path(location)
  if location.ancestors?
    location_child_path(location.root, location)
  else
    location_path(location)
  end
end

And lastly, in my views I simply call my helper method to generate the correct URL:

<%= link_to location.name, get_full_location_path(location) %>

This seems to be working nicely, but my next task is to extend this to cover grandparents and great-grandparents. Any advice is appreciated!

Kobius
  • 674
  • 7
  • 28