2009-11-23 3 views
1

В моем приложении я пытаюсь заставить свой API подражать GitHub в том, как он имеет формат (.:) В начале маршрута, а не добавляет он необязательно в конце.Перемещение атрибута формата в маршрутизации от конца до начала маршрута

Вот мой код, который «работает», но могут быть проигнорированы:

map.namespace :api do |api| 
    api.namespace :v1 do |v1| 
    v1.resource :company, :path_prefix => "api/v1/:format" 
    end 
end 

Я могу пойти в /api/v1/xml/company.json и Rails обеспечит json как params[:format], а не xml.

Когда я бегу rake routes я получаю

/api/v1/:format/company(.:format) 

Есть ли способ, чтобы заставить его вернуть:

/api/v1/:format/company 

Заранее спасибо!

ответ

1

EmFi правый. Я не ответил на этот вопрос, просто высказал свое мнение.

Включите следующий код в файл инициализатора в директории инициализаторов config внутри вашего приложения Rails. То, что вы называете файлом, не имеет значения для фреймворка, так как все файлы в этом каталоге находятся в пути загрузки. Я предлагаю вам назвать это actioncontroller_resource_monkeypatch.rb, чтобы сделать намерение понятным.

ActionController::Resources.module_eval do 
    def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil, resource_options = {}) 
    if resource.has_action?(action) 
     action_options = action_options_for(action, resource, method, resource_options) 

     formatted_route_path = route_path.match(/\/:format\//) ? route_path : "#{route_path}.:format" 

     if route_name && @set.named_routes[route_name.to_sym].nil? 
     map.named_route(route_name, formatted_route_path, action_options) 
     else 
     map.connect(formatted_route_path, action_options) 
     end 
    end 
    end 
end 

Мой ответ использует тот же метод, как EmFi-х, т.е. путем monkeypatching ActionController::Resources#map_resource_routes. Я решил бросить свою шляпу на ринг, потому что она не предлагала полную реализацию, которая оставалась для вас упражнением. Я также считаю, что тройное назначение formatted_route_path намного чище и более кратким, чем блок if-else/if-else. Еще одна строка кода вместо пяти! Это самое меньшее, что я могу сделать за 200 щедростей!

Теперь запустите rake routes

new_api_v1_company GET /api/v1/:format/company/new {:action=>"new", :controller=>"api/v1/companies"} 
edit_api_v1_company GET /api/v1/:format/company/edit {:action=>"edit", :controller=>"api/v1/companies"} 
    api_v1_company GET /api/v1/:format/company  {:action=>"show", :controller=>"api/v1/companies"} 
        PUT /api/v1/:format/company  {:action=>"update", :controller=>"api/v1/companies"} 
        DELETE /api/v1/:format/company  {:action=>"destroy", :controller=>"api/v1/companies"} 
        POST /api/v1/:format/company  {:action=>"create", :controller=>"api/v1/companies"} 

TADA!

0

Я считаю, что (.format) не является обязательным (это то, что скобка имею в виду), так /api/v1/:format/company(.:format) == /api/v1/:format/company

Если вы хотите изменить это больше, чем это, вам нужно взломать/обезьяна патч рельсы.

+0

Я понимаю, но при условии, что я поместил другое расширение в конце своего URI, я могу переопределить формат custom: format, там должен быть предоставлен формат, вот почему я считаю, что я должен поместить его здесь. – Garrett

+0

Просто прямо, я не хочу, чтобы пользователь мог добавлять формат вообще. – Garrett

0

Я просто делаю снимок здесь (я буду проверять и обновлять завтра, когда я могу играть с кодом), но не могли бы вы избежать использования :format и сделать что-то вроде этого?

маршруты:

map.connect ':controller/:return_type/:action/:id' 

контроллер:

@results = MyObject.all 

case :return_type 
    when 'xml' render :text => @results.to_xml 
    when 'json' render :text => @results.to_json 
end 

Если дело слишком запутанна/некрасиво, вы можете легко создать вспомогательный метод, который имитирует поведение, которое вы ищете для.

+0

Я бы по-прежнему хотел бы использовать стандартный response_to, я верю, что когда вы начнете двигаться и создаете свой собственный, вы не получите такую ​​же функциональность. – Garrett

2

Это потребует серьезной подделки. Маршрутизация также является одной из наиболее сложных областей кода Rails, которая соединяет входящие HTTP-запросы с вашим кодом и генерирует URL.

Простите меня, если я буду самонадеянным, но, насколько я могу судить, ваша причина идти против конвенции Rails заключается в том, чтобы имитировать другую компанию. Другими словами, вы готовы игнорировать коллективную мудрость вкладчиков Rails в пользу принятия решения, принятого несколькими разработчиками.

Я думаю, вы должны спросить себя, почему вы хотите, чтобы это достаточно убедительно, чтобы быть соразмерным требуемым усилиям?

Чем сложнее сделать что-то иное, чем путь Rails, тем более строго нужно подвергать сомнению их решение. Наличие значительных барьеров обычно свидетельствует о том, что есть лучший способ сделать что-то.

0

Steve Graham says everything Это нужно сказать, но вопрос с 200 вознаграждением за заслуги заслуживает правильного ответа. Как бы плохо ни советовали. Кроме того, похоже, что это может быть полезно.

Патч обезьяны на удивление прост. Вам просто нужно переопределить ActionController :: Resource # map_resource_routes следующим образом.

def map_resource_routes(map, resource, action, route_path, 
     route_name = nil, method = nil, resource_options = {}) 
    if resource.has_action?(action) 
    action_options = action_options_for(action, resource, method, resource_options) 

    unless route_path.match(/\/:format\//)  # new line of code 
     formatted_route_path = "#{route_path}.:format" 
    else           # new line of code 
     formatted_route_path = route_path   # new line of code 
    end           # new line of code 

    if route_name && @set.named_routes[route_name.to_sym].nil? 
     map.named_route(route_name, formatted_route_path, action_options) 
    else 
     map.connect(formatted_route_path, action_options) 
    end 
    end 
end 

Включение исправления в код включает в себя либо заплат ваши рельсы камень или сделать плагин, оба из которых являются довольно просто и оставляется в качестве упражнения для читателя.

Код работает, пропуская строку, которая добавляет формат опций всем маршрутам, если он уже содержит параметр с именем format.

Редактировать: Ссылка на ответ Стива Грэма, на который ссылается это решение. В первоначальное время публикации был только один.

-1

Я использовал этот код:

ActionController::Routing::Routes.draw do |map| 
    map.namespace(:v1, :path_prefix => "api/v1/:format") do |v1| 
    v1.resources :repositories 
    end 
end 

URL-адрес становится апи/v1/[JSON/XML/все]/< успокоительных URL здесь идет >

Мне нравится идея пространства имен версии тоже (как и в вашем вопросе):

class V1::RepositoriesController < V1::ApplicationController 

end 

Хотя этот метод позволяет поместить формат в UR L дважды: Вам не нужно следить за тем, чтобы пользователи не помещали формат в URL два раза, и ваши пользователи должны убедиться, что они не помещают формат в URL дважды.

Не тратьте время на решение PEBKAC.

+0

Почему downvote? Я считаю, что это законное решение. –

Смежные вопросы