Ресурсы Rails RESTful, использующие to_param для поля, содержащего символы-разделители
-
09-09-2019 - |
Вопрос
Я хочу, чтобы мое приложение Rails 2.3.2 отвечало на URL-адреса и генерировало их следующим образом:
/websites/asd.com
/websites/asd.com/dns_records/new
В моем config/routes.rb у меня есть:
map.resources :websites, :has_many => :dns_records
map.resources :dns_records, :belongs_to => :website
Затем я могу получить доступ к таким ресурсам, как:
/websites/1
/websites/1/dns_records
Изменяя модель моего веб-сайта, я могу генерировать лучшие URL-адреса следующим образом:
class Website < ActiveRecord::Base
def to_param
domain_name
end
...
end
# app/views/websites/index.erb
<% @websites.each do |w| %>
<%= link_to "Show #{w}", website_path(w) %>
<% end %>
# Produces a link to:
/websites/example_without_periods_in_name
Однако для доменных имен, содержащих символы '.', Rails становится недовольным.Я полагаю, это связано с тем, что символ '.' определен в ActionController::Routing::SEPARATORS , в котором перечислены специальные символы для разделения URL-адреса.Это позволяет вам делать такие вещи, как /websites/1.xml .
ИТАК, есть ли чистый способ разрешить символы '.' в URL-адресах RESTful?
Я попытался переопределить ActionController::Routing::SEPARATORS, чтобы не включать '.' , что является совершенно плохим способом решения проблемы.Это портит сгенерированные URL-адреса, добавляя к ним ".:format".
Я также знаю, что могу добавить:requirements => { :id => regexp } в мой config/routes.rb, чтобы соответствовать доменному имени, которое включает '.' (без этого params[:id] устанавливается на часть доменного имени перед первым '.'), но это не помогает в генерации URL-адресов / путей RESTfully.
Большое спасибо :) Ник
Решение
Решил проблему, с большой благодарностью http://poocs.net/2007/11/14/special-characters-and-nested-routes (и увидеть http://dev.rubyonrails.org/ticket/6426 для дополнительной справки)
Мне нужно было добавить:requirements => { :website_id => regexp } для каждого вложенного маршрута, который также должен был включать доменное имя с точками в нем.
Вот мой рабочий маршрут:
map.resources :websites, :requirements => { :id => /[a-zA-Z0-9\-\.]+/ } do |websites|
websites.with_options :requirements => { :website_id => /[a-zA-Z0-9\-\.]+/ } do |websites_requirements|
websites_requirements.resources :dns_records
end
end
<%= link_to 'New DNS Record', new_website_dns_record_path(@website) %>
# Produces the URL
/websites/asd.com/dns_records/new
Призыв к
websites.with_options
просто соответствует DRY, так что : требования не обязательно указывать для всех вложенных маршрутов для веб-сайтов.Так что я тоже мог бы иметь
websites_requirements.resources :accounts
websites_requirements.resources :monthly_bandwidth_records
etc.
Другие советы
Это интересный вопрос.Я не думаю, что ты можешь избавиться от плохого '.:format'
добавляется в конец, если вы выполняете базовую map.resources
.Если вам нужны точки в именах, вы не соответствуете обычным стилям rails, и я думаю, что пользовательский маршрут может подойти, если вы абсолютно ПОТРЕБНОСТЬ '.' в URL-адресе.
Однако, возможно, вам следует рассмотреть возможность изменения вашего определения to_param
.Что бы вы подумали об использовании следующего?
def to_param
domain_name.sub('.','_dot_')
end
Я думаю, если вы используете это для управления веб-сайтами клиентов, это довольно элегантный способ генерировать приятные (и оптимизированные для SEO) URL-адреса, такие как
/websites/asd_dot_com/dns_records/new
/websites/asd_dot_com/
Некоторое время назад у меня была похожая проблема, и я пришел к аналогичному решению.Использование /.+/ в качестве требования к рассматриваемому параметру у меня сработало нормально.