user4227507
user4227507

Reputation:

Update Second Drop Down Menu Based on Selection in the First Drop Down

I am building a cinema application in Ruby on Rails and am currently working on the booking system. What I want to be able to do is select a film from a drop down menu, and then the show times for that film are displayed in a drop down menu, the user can select a show time and then the seats available are displayed in a drop down menu.

I have watched this video: https://www.youtube.com/watch?v=GYg6s-b1XGo and have looked at many other sites but what I want to do is a bit more complicated.

Ok, so my models/bookings.rb:

class Booking < ActiveRecord::Base
    belongs_to :user
    belongs_to :showing
    belongs_to :seat
end

models/showing.rb:

class Showing < ActiveRecord::Base
  belongs_to :film
  has_many :bookings
  belongs_to :screen

  def showing_times
    "#{show_date.strftime("%e %b %Y")} @ #{show_time.strftime("%H:%M")}"
  end
end

models/seats.rb:

class Seat < ActiveRecord::Base
    belongs_to :screen
    has_many :bookings

    def seats_available
        "#{row_letter}#{row_number}"
    end
end

This is where it gets complicated, my views/bookings/_form.html.erb:

             <%= form_for @booking do |f| %>
                <%= f.hidden_field :user_id %>
                <%= image_tag "thor_hammer.jpg",:size => "900x250" %>
                <td width="300px">

                    <br><%= f.label :film_id, 'Film:' %>
                    <br><%= f.collection_select :film_id, Film.all, :id,:title_info %>

                    <br><%= f.label :showing_id, 'Showing:' %>
                    <br><%= f.collection_select :showing_id, Showing.all, :id,:showing_times %>

                    <br><%= f.label :seat_id, 'Seat ID:' %>
                    <br><%= f.collection_select :seat_id, Seat.all, :id,:seats_available %><br>
                </td>
                <td width="300px">
                    <div class="actions">
                      <%= f.submit %>
                    </div>
                    <br>    
                    <%= render "/error_messages", :message_header => "Cannot save: ", :target => @booking %> 
                </td>
            <% end %> 

This is where it gets complicated because the line <%= f.collection_select :film_id, Film.all, :id,:title_info %> causes the error:

NoMethodError in Bookings#new 
undefined method `film_id' for #<Booking:0x584e6b0>

Because the bookings data table does not store the film, it stores the showing time and this has the film associated with it, this is the same for the seats: the user needs to be able to select a showing to select the seat but the showings table is associated with the screens table, which is associated with the seats.

To make this clearer, here is the schema:

create_table "bookings", force: :cascade do |t|
  t.integer  "user_id"
  t.integer  "showing_id"
  t.integer  "seat_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "films", force: :cascade do |t|
  t.string   "title"
  t.string   "synopsis"
  t.string   "director"
  t.string   "cast1"
  t.string   "cast2"
  t.string   "cast3"
  t.date     "release_date"
  t.string   "warnings"
  t.datetime "created_at",     null: false
  t.datetime "updated_at",     null: false
  t.string   "image_url"
  t.string   "certificate_id"
  t.integer  "category_id"
  t.integer  "hours"
  t.integer  "minutes"
  t.string   "video_url"
end

create_table "screens", force: :cascade do |t|
  t.string   "name"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "seats", force: :cascade do |t|
  t.string   "row_letter"
  t.integer  "row_number"
  t.integer  "screen_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "showings", force: :cascade do |t|
  t.date     "show_date"
  t.time     "show_time"
  t.integer  "film_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.integer  "screen_id"
end

Has anyone got any suggestions?

Upvotes: 0

Views: 201

Answers (1)

Marius Pop
Marius Pop

Reputation: 1461

You are trying to set the film_id of an instance of the Booking class. You are correct to notice that you do not have a film_id in the bookings table.

The easiest way to accomplish what you desire is simply to add a film_id to the bookings table and to create a has_one and belongs_to association between Booking and Film.

Another way to accomplish this, that will require you to dive deeper into rails is to use accepts_nested_attributes_for. Here's a good tutorial and here's a newer tutorial if you run into any issues with the first one. This will allow you to not have to create redundant associations.

UPDATE 1

After looking closer at what you are trying to do I realized that you are not trying to create a new resource (film) so please disregard my previous comment about nested attributes.

The solution to what you are trying to do involves a few moving parts that are a little too long to give in an answer like this. However, here is a summary that may guide you while you try to figure it out:

  • You need a separate form to select the film first
  • Based on the film selection you can use ajax to fetch all the showings that belong to that film (For this you need to read up on ajax; you also need to read up on how to expose your data via a json endpoint in rails) You will end up passing an id of the film the user has selected and you will return the result of this query: Showing.where(film_id: <id>)
  • After you managed to get that data you need to populate it in a second form that ends up displaying only the showings associated with that film.

This seems a bit complicated for what you are trying to do. What I would recommend is that you either:

  • spend some extra time on figuring out how to structure your models a little differently
  • or that you don't allow the users to select the film and then the showings on the same page (dynamically). Make them select the film first. After they selected the film they are redirected to a page where they can select the showings. This would be a worse experience for the user but it would enable you to understand rails a little better (ajax and javascript wouldn't be required in this scenario).

I assume you're doing this to try to get a better grasp of rails, so I hope this information helps you. Good luck!

Upvotes: 0

Related Questions