DEV Community

Discussion on: Custom (Dynamic) Rails Routes via Database Query

Collapse
 
sowenjub profile image
Arnaud Joubay

Hey Brad, for your curiosity, here's how I would approach this.

First, I would use a scope instead of a class method and remove take from it to leave it chainable as is expected from a scope.
Take performs the query immediately and you will get an array of values instead of an object that can be chained with another query method (where, etc.).

class Trail < ApplicationRecord
  belongs_to :park
  scope :in_state, -> (state) { joins(:park).where(parks: { state: state }) }
end
Enter fullscreen mode Exit fullscreen mode

There's no more pagination, but this should really be in the controller, just like the logic about the trails.
I would introduce a private method to filter trails and fall back on the default all scope if no state is provided.
I use limit instead of take to postpone any query and leave the @trails chainable in case we need to filter further down the road. I introduced an optional :per param that you can send along with your query to have a more flexible limit (eg. trail_state_path("CA", per: 100))
I would also save the selected state to use it in the view.

class TrailsController < ApplicationController
  def index
    @state = params[:state]
    @trails = filtered_trails || Trail.all
  end

  private
    def filtered_trails
      return unless params[:state].present?
      Trail.in_state(params[:state]).limit(params[:per].presence || 10)
    end
end
Enter fullscreen mode Exit fullscreen mode

And now you don't need to have two blocks anymore for your list of trails in your index.
Also, you can use collection rendering instead of iterating.

<h2 class="font-weight-light text-center mt-5">See Trails by State</h2> 
<div class="row mx-md-n5 mt-5">
    <h3 class="font-weight-light text-center col px-md-3 d-flex justify-content-center"><%= link_to "California Trails", trail_state_path("CA")%><h3>
    <h3 class="font-weight-light text-center col px-md-3"><%= link_to "Washington Trails", trail_state_path("WA")%></h3>
    <h3 class="font-weight-light text-center col px-md-3 d-flex justify-content-center"><%= link_to "All Trails", trails_path%><h3>
</div>

<div class=(@state.present? ? "album" : "album font-weight-light")>
   <div class="container-fluid text-center">
        <div class="d-flex justify-content-center row">
          <%= render partial: "trails/trail", collection: @trails %>
        </div>
   </div>
</div>
Enter fullscreen mode Exit fullscreen mode

You will probably want to make the currently selected state bolder, but I'll leave it there.

Collapse
 
brad_beggs profile image
Brad Beggs

@arnaud Joubay Thank you for the time and suggestions. I'll remember the idea of keeping things as objects so one has the flexibility later. I like the refactor of removing the two blocks to show the states via collection rendering (a new concept for me).

Collapse
 
sowenjub profile image
Arnaud Joubay

You're welcome, glad you found my comment interesting.