Constrângeri Rails routes.rb (Revizuirea codului, Ruby, Ruby Pe Șine)

DaniG2k a intrebat.

Încerc să mă gândesc la o modalitate mai bună de a scrie aceste rute în fișierul routes.rb:

Rails.application.routes.draw do
  root 'home#index'

  s = /section1|section2|section3|section4/
  y = /d{4}/
  m = /d{1,2}/

  resources :articles, except: [:index, :show]

  # The slug will replace the default params[:id] of the following resources: 
  resources :articles, only: [:index, :show], path: '/:section/:year/:month', as: :my_articles, constraints: {:section => s, :year => y, month: m}

  get ':section/:year/:month', to: 'articles#by_month', as: :month, constraints: {section: s, year: y, month: m}
  get ':section/:year', to: 'articles#by_year', as: :year, constraints: {section: s, year: y}
  get ':section', to: 'articles#by_section', as: :section, constraints: {section: s}
end

Asta îmi permite să caut articole după secțiune, după an+secțiune, după lună+secțiune+an. De asemenea, îmi permite să adaug un slug frumos la URL-uri.

Una dintre probleme este că constrângerile sunt comune tuturor acestor rute. Mă întreb dacă există o modalitate mai inteligentă de a scrie acest lucru. Cineva mi-a sugerat să folosesc preocupări, dar nu am găsit o modalitate de a face asta.

Nu este un schimbător de joc, dar sunt curios cum pot să scriu acest lucru corect.

2 răspunsuri
DaniG2k

Am înțeles:

Rails.application.routes.draw do
  root 'home#index'

  resources :articles, except: [:index, :show]
  constraints section: /section1|section2|section3|section4/ do
    constraints year: /d{4}/ do
      constraints month: /d{1,2}/ do
        resources :articles, only: [:index, :show], path: '/:section/:year/:month', as: :my_articles
        get ':section/:year/:month', to: 'articles#by_month', as: :month
      end
      get ':section/:year', to: 'articles#by_year', as: :year
    end
    get ':section', to: 'articles#by_section', as: :section
  end

Simt că este mult mai curat 🙂

rui

Eu nu aș folosi constrângeri de rute deloc aici și aș păstra restful controller pentru simplitate și întreținere ușoară.

class ArticlesController < ApplicationController
  def index
    @articles = Article.by_section(params[:section])
                  .by_year(params[:year])
                  .by_month(params[:month])
  end
end

apoi definiți domenii de aplicare în model pentru a permite parametrii lipsă:

class Article < AR::Base
 scope :by_section, ->(section) { section.present? ? where(section: section) : all }
 scope :by_year,    ->(year)    { year.present?    ? where(year: year)       : all }
 scope :by_month,   ->(month)   { month.present?   ? where(month: month)     : all }
end

să se ocupe prin intermediul unei singure rute:

get '/:section(/:year(/:month))', to: 'articles#index'

și în cele din urmă în vizualizări ai putea face:

<%= link_to 'In section 1', articles_path(section: 1) %>
<%= link_to 'In section 1 in 2014', articles_path(section: 1, year: 2014) %>

Poate doriți să gestionați cazurile în care utilizatorul manipulează URL-ul și, de exemplu, pune un șir de caractere în loc de an – probabil că va rezulta o eroare din baza de date.

Personal, cred că este perfect corect să pedepsiți utilizatorii care manipulează manual URL-urile cu o pagină de eroare (500). Utilizând constrângeri ar da eroare oricum, dar cu 404 în schimb.

Dacă simțiți că trebuie să vă asigurați că utilizatorului i se permite, de exemplu, să vizualizeze doar articolele din secțiunile selectate, puteți adăuga un alt domeniu de aplicare:

scope :in_allowed_sections, -> { where(section: ['section 1', 'section 2']}

În cazul în care un utilizator rău intenționat manipulează manual URL-ul, acest lucru ar duce la o interogare SQL validă:

where section in ('section 1', 'section 2') and section = 'section 3'

iar utilizatorul va primi o pagină corectă (200), dar fără a afișa niciun articol.

Comentarii

  • Am încercat această metodă și s-a dovedit a fi la fel de complexă ca și prima metodă. Mulțumesc totuși pentru sugestie!-  > Por DaniG2k.