为什么我无法从关联表中获取数据?

时间:2015-02-18 15:04:32

标签: ruby-on-rails ruby associations relationship models

在我的Ruby on Rails应用程序中,我试图显示预订用户的first_name和last_name。

在预订/ index.html.erb上我有这个:

<% @bookings.each do |booking| %>
                                    <tr>
                                        <td><%= booking.user.first_name %> <%#= booking.user.last_name %></td>
                                        <td><%= booking.showing.film.title %></td>
                                        <td><%= booking.showing.show_date %></td>
                                        <td><%= booking.showing.show_time.strftime("%H:%M") %></td>
                                        <td></td>
                                        <td><%= booking.seat.row_letter %><%= booking.seat.number %></td>
                                        <td style="padding-right:65px">
                                            <%#= link_to 'Edit', edit_user_path(user) %>  
                                            <%#= link_to 'Show', user_path(user) %>  
                                            <%#= link_to 'Destroy', user_path(user), method: :delete, data: { confirm: 'Are you sure?' } %>
                                        </td>
                                    </tr>
                                <% end %>

booking.showing.film.title和下面的代码有效但booking.user.first_name我收到了错误:

NoMethodError in Bookings#index     
undefined method `first_name' for nil:NilClass

但我认为我的模型设置正确,user.rb:

has_many :bookings

bookings.rb:

belongs_to :user

bookings_controller:

class BookingsController < ApplicationController
  before_action :set_booking, only: [:show, :edit, :update, :destroy]

  # GET /bookings
  # GET /bookings.json
  def index
    @bookings = Booking.all
  end

  # GET /bookings/1
  # GET /bookings/1.json
  def show
  end

  # GET /bookings/new
  def new
    @booking = Booking.new
  end

  # GET /bookings/1/edit
  def edit
  end

  # POST /bookings
  # POST /bookings.json
  def create
    @booking = Booking.new(booking_params)

    respond_to do |format|
      if @booking.save
        format.html { redirect_to @booking, notice: 'Booking was successfully created.' }
        format.json { render :show, status: :created, location: @booking }
      else
        format.html { render :new }
        format.json { render json: @booking.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /bookings/1
  # PATCH/PUT /bookings/1.json
  def update
     respond_to do |format|
      if @booking.update(booking_params)
        format.html { redirect_to @booking, notice: 'Booking was successfully updated.' }
        format.json { render :show, status: :ok, location: @booking }
      else
        format.html { render :edit }
        format.json { render json: @booking.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /bookings/1
  # DELETE /bookings/1.json
  def destroy
     @booking.destroy
    respond_to do |format|
      format.html { redirect_to bookings_url, notice: 'Booking was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_booking
      @booking = Booking.find(params[:id])
    end

   # Never trust parameters from the scary internet, only allow the white list through.
    def booking_params
      params.require(:booking).permit(:showing_id, :user_id, :seat_id)
    end
end

我错过了什么吗?属性名称和表名称是正确的。

3 个答案:

答案 0 :(得分:1)

使用多个点违反了Law of Demeter,被视为错误做法。要遵循Demeter法则,您可delegate user模型的名称,并在user类中创建实例方法以返回全名,

预订课程

class Booking < ActiveRecord::Base
  belongs_to :user
  delegate :full_name, to: :user, prefix: true, allow_nil: true
end

用户类

class User < ActiveRecord::Base
  has_many :bookings

  def full_name
    "#{first_name} #{last_name}"
  end
end

视图

<td><%= booking.user_full_name %></td>

如果用户是nil,此功能将正常返回,而不会抱怨没有用户。

委托方法调用总是更好(不要特意将delegate视为关键字),而不是调用那么多点,例如,booking.showing.film.title,有很多事情可以去错误的是,如果预订或显示或电影更改了任何属性,您需要继续迭代所有视图并每次修复每个视图,而不是尝试创建一个名为booking.film_title的集中函数,然后你只需要将它保存在一个地方。

答案 1 :(得分:0)

因为user为零,所以booking.user会抛出错误

只需尝试此booking.try(:user).try(:first_name)

即可
 <% @bookings.each do |booking| %>
                                    <tr>
                                        <td><%= booking.try(:user).try(:first_name) %> <%= booking.try(:user).try(:last_name) %></td>
                                        <td><%= booking.showing.film.title %></td>
                                        <td><%= booking.showing.show_date %></td>
                                        <td><%= booking.showing.show_time.strftime("%H:%M") %></td>
                                        <td></td>
                                        <td><%= booking.seat.row_letter %><%= booking.seat.number %></td>
                                        <td style="padding-right:65px">
                                            <%#= link_to 'Edit', edit_user_path(user) %>  
                                            <%#= link_to 'Show', user_path(user) %>  
                                            <%#= link_to 'Destroy', user_path(user), method: :delete, data: { confirm: 'Are you sure?' } %>
                                        </td>
                                    </tr>
                                <% end %>

有关点击try

的零处理的详细信息

答案 2 :(得分:0)

您有正确的设置关联。 但问题是,您在创建user_id记录时添加了booking

<% @bookings.each do |booking| %>
  <tr>
     <td><%= booking.user.try(:first_name) %> <%#= booking.user.try(:last_name) %></td>
     <td><%= booking.showing.film.title %></td>
     <td><%= booking.showing.show_date %></td>
     <td><%= booking.showing.show_time.strftime("%H:%M") %></td>
     <td></td>
     <td><%= booking.seat.row_letter %><%= booking.seat.number %></td>
     <td style="padding-right:65px">
       <%#= link_to 'Edit', edit_user_path(user) %>  
       <%#= link_to 'Show', user_path(user) %>  
       <%#= link_to 'Destroy', user_path(user), method: :delete, data: { confirm: 'Are you sure?' } %>
     </td>
  </tr>
<% end %>

使用方法try将确保不会发生错误

booking.user.try(:first_name) # display user first name if exist
booking.user.try(:last_name)  # display user last  name if exist

打开rails c并检查您的booking记录中没有user_id