2015-09-30 4 views
1

Я использую рельсы 4.2. Я создал форму, которая подчиняется определенному действию в моем контроллере. Вот начало кода формы и определения контроллера:Странное поведение маршрутизации в рельсах

view.html.erb

<div id="account-booking" class="tab-pane"> 
    <%= form_for @booking_info, url: { action: 'book' } do |b| %> 
     <fieldset class="group column-1"> 
     <legend>Booking Preference for <%= Rails.configuration.x.app_settings.year %></legend> 

     <div class="group column-full radio-list"> 
      <%= label_tag('Select Room Type') %> 
      <% @available_rooms.each do |rt| %> 
       <div class="radio-item"> 
       <!-- 
       <%= b.radio_button :room_type_id, rt.id, :class => 'rb_room_type inline', :onclick => fetch_room_info_path(:id => rt.id), :remote => true %> 
       <%= b.radio_button :room_type_id, rt.id, :class => 'rb_room_type inline', :onclick => 'render_room_info('+ rt.id.to_s + ');' %> 
       --> 
       <%= b.radio_button :room_type_id, rt.id, :class => 'rb_room_type inline' %> 
       <%= content_tag :span, rt.name %> 
       <a data-toggle="tooltip" data-placement="right" title="<%= rt.description %>"> 
        <%= image_tag "tooltip.png", :class=>"tooltip-icon" %> 
       </a> 
       </div> 
      <% end %> 

      <%= b.label :roommate_preference, 'Roommate Preference' %> 
      <%= b.text_area :roommate_preference, :class => 'form-control' %> 

      <div class="account-checkbox-options"> 
      <%= b.label :is_flexible, class: 'checkbox inline' do %> 
       <%= b.check_box :is_flexible %> 
       I am flexible with regards to my room choice. 
      <% end %> 
      </div> 
     </div> 

     <!-- 
     <div id="estimated-due" class="group column-2"> 

     </div> 
     --> 
     </fieldset> 

     <fieldset class="group column-2 account-preferences"> 
     <legend>Your Room Information for <%= Rails.configuration.x.app_settings.year %></legend> 
     <div class="group column-1"> 
      <div class="group column-full add-tabbing"> 
      <%= label_tag('Selected Room:') %> 
      <span><%= @booking_info.room_type.blank? ? '<No Room Selected>' : @booking_info.room_type.name %></span> 
      </div> 

      <div class="group column-full add-tabbing"> 
      <%= label_tag('Assigned Room:') %> 
      <span><%= @booking_info.assigned_type.blank? ? '<No Room Assigned>' : @booking_info.assigned_type.name %></span> 
      </div> 
     </div> 
     <div class="group column-2"> 
      <div class="group column-full add-tabbing"> 
      <%= label_tag('Total Due:') %> 
      <span ><%= number_to_currency(@booking_info.total_due.blank? ? 0.00 : @booking_info.total_due) %></span> 
      </div> 
      <div class="group column-full add-tabbing"> 
      <%= label_tag('Current Balance:') %> 
      <span><%= number_to_currency(@booking_info.outstanding_balance.blank? ? 0.00 : @booking_info.outstanding_balance) %></span> 
      </div> 
     </div> 
     <% unless @booking_info.assigned_type.blank? %> 
      <div class="group column-full"> 
       <h2>Assigned Room Information</h2> 
      </div> 
     <% end %> 
     </fieldset> 

     <div class="account-buttons"> 
     <%= b.submit 'Submit', class: 'btn btn-danger' %> 
     <%= link_to 'Cancel', '/pages/home', class: 'link-button-cancel' %> 
     </div> 

    <% end %> 
</div> 

account_controller.rb

def book 
    @booking = PersonRoom.new(booking_params) 
    @requested_room = RoomType.find(params[:person_room][:room_type_id]) 
    @booking.room_type = @requested_room 

    if update_booking @booking 
     redirect_to :controller => 'account', :action => 'view' 
    else 
     render('view') 
    end 
end 

Все это прекрасно работает, когда нет записи PersonRoom (например, если я делаю вставку). Однако, если я попытаюсь обновить запись, используя ту же самую точную форму/действие (потому что и представление, и действие абсолютно одинаковы независимо от того, вставляю ли я или обновляю), я получаю сообщение об ошибке, когда я нажимаю «Отправить», :

нет маршрута матчей [PATCH] "/ счет/книга"

Это не имеет никакого смысла. Я на той же странице. Я просто использовал весь этот код для создания записи, поэтому маршрут явно существует (потому что он вызывает/account/book). Теперь я хочу обновить, но вдруг маршрут не соответствует? И он даже не врывается в код, потому что он не вызывает действие контроллера. Это имеет для меня смысл. Надеюсь, кто-то может помочь.

+0

Предоставляете ли вы идентификатор вместе с запросом при обновлении организация? – Makoto

+1

Каков ваш файл routes.rb? Обновление не работает из-за типа запроса (PATCH), возможно, не из-за чего-либо еще. –

ответ

0

Я вздрогнула, когда глядя на свой код, вот как я бы это сделал:

#config/routes.rb 
resources :rooms do 
    resources :bookings #-> url.com/rooms/:room_id/bookings/new 
end 

#app/controllers/bookings_controller.rb 
class BookingsController < ApplicationController 
    before_action :set_room 
    def new 
     @booking = room.bookings.new 
    end 

    def create 
     @booking = room.bookings.new booking_params 
     @booking.save 
    end 

    def update 
     @booking = room.bookings.update booking_params 
    end 

    private 

    def set_room 
     @room = Room.find params[:room_id] 
    end 

    def booking_params 
     params.require(:booking).permit(:x, :y, :z) 
    end 
end 

Эта установка является довольно стандартным с Rails (IE resourceful routes):

Браузер запроса страницы из Rails, сделав запрос на URL с использованием конкретный метод HTTP, такие как GET, POST, пластыри, PUT и DELETE. Каждый метод представляет собой запрос на выполнение операции над ресурсом. Маршрут ресурсов сопоставляет ряд связанных запросов к действиям в одном контроллере .

Соблюдение этого принципа, скорее всего, устранит ваши «странные» ошибки маршрутизации из-за их сплоченности с другими аспектами системы Rails.

Например:

#app/controllers/accounts_controller.rb 
class AccountsController < ApplicationController 
    #-> this shouldn't have a "book" action unless necessary. Your case is not necessary 
end 

-

Проблема у вас есть то, что вы не придерживаясь конвенции рельсам сохранения системы объектно-ориентированной.

Важность этого огромна; Rails предназначен для того, чтобы сделать его максимально простым для объектов данных CRUD (create read update destroy).Эти объекты построены из базы данных в «модели»:

enter image description here

Я использую эту картину много - он показывает, как Rails должен работать. Вы строите объекты в своем Models, которыми вы управляете в своих контроллерах. Представления показывают все это пользователю.

Таким образом, когда вы смотрите на код, я хотел бы сохранить его как можно более простым:

#app/models/room.rb 
class Room < ActiveRecord::Base 
    has_many :bookings 
    has_many :users, through: :bookings 
    belongs_to :type 
end 

#app/models/booking.rb 
class Booking < ActiveRecord::Base 
    belongs_to :room 
    belongs_to :user 
end 

#app/models/user.rb 
class User < ActiveRecord::Base 
    has_many :bookings 
    has_many :rooms, through: :bookings 
end 

Это позволит вам назвать следующие:

@room = Room.find 1 
@room.bookings #-> collection of bookings per room 

Вы также можете сделайте что-то вроде следующего (простого) для просмотров:

#app/views/bookings/new.html.erb 
<%= form_for @booking do |f| %> 
    <%= f.text_field :x %> 
    <%= f.text_field :y %> 
    <%= f.text_field :z %> 
    <%= f.submit %> 
<% end %> 
+0

Итак, я понимаю, что вы говорите. Но даже если бы я организовал его таким образом, будет ли он работать без изменений, внесенных в route.config? Основная проблема заключалась в том, что маршрут был настроен только на поиск глаголов get и post, и этот вызов использовал глагол патча, чтобы маршрут не был настроен. Разве мне еще не пришлось бы добавлять код в мой ответ на route.config, даже если бы я реорганизовал контроллеры, как вы предлагаете? –

+0

Если вы просто хотели, чтобы он работал с 'put/patch', вы должны использовать атрибут' via' для их определения. Проблема глубже, чем это; как указано в ответе. –

+0

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

0

Я нашел проблему. Это было что-то действительно глупое. Я имел следующую строку в моей route.config:

match ':controller(/:action(/:id))', :via => [:get, :post] 

Мне просто нужно, чтобы изменить это:

match ':controller(/:action(/:id))', :via => [:get, :post, :patch, :put, :delete] 

Теперь он обрабатывает обновления (то есть патч/ставить)

+0

Этот код на самом деле не так хорош - позвольте мне написать ответ, чтобы дать вам несколько идей. –