为什么我无法从关联的 table 获取数据?
Why can I not get data from an associated table?
在我的 Ruby on Rails 应用程序中,我试图显示进行预订的用户的 first_name 和 last_name。
在 bookings/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
我错过了什么吗?属性名称和 table 名称正确。
因为 user
是 nil 所以 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
您已正确设置关联。
但问题是,您在创建 booking
记录时是否添加了 user_id
。
<% @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
使用多个点违反了 Law of Demeter
并被视为 不良 做法。要遵循得墨忒耳法则,可以将delegate
名称改为user
模型并在user
创建实例方法class改为return全名,
预订class
class Booking < ActiveRecord::Base
belongs_to :user
delegate :full_name, to: :user, prefix: true, allow_nil: true
end
用户class
class User < ActiveRecord::Base
has_many :bookings
def full_name
"#{first_name} #{last_name}"
end
end
风景
<td><%= booking.user_full_name %></td>
如果用户 nil
此函数将 return 优雅地 return nil 而不会抱怨没有用户。
委托方法调用总是更好(不要指 delegate
作为关键字)而不是调用这么多点,以 booking.showing.film.title
为例,有很多东西这可能会出错,如果预订或放映或电影更改了任何属性,您需要不断迭代所有视图并每次修复每一个视图,而不是尝试创建一个集中函数,例如 booking.film_title
,那么你只需要在一个地方维护它。
在我的 Ruby on Rails 应用程序中,我试图显示进行预订的用户的 first_name 和 last_name。
在 bookings/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
我错过了什么吗?属性名称和 table 名称正确。
因为 user
是 nil 所以 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
您已正确设置关联。
但问题是,您在创建 booking
记录时是否添加了 user_id
。
<% @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
使用多个点违反了 Law of Demeter
并被视为 不良 做法。要遵循得墨忒耳法则,可以将delegate
名称改为user
模型并在user
创建实例方法class改为return全名,
预订class
class Booking < ActiveRecord::Base
belongs_to :user
delegate :full_name, to: :user, prefix: true, allow_nil: true
end
用户class
class User < ActiveRecord::Base
has_many :bookings
def full_name
"#{first_name} #{last_name}"
end
end
风景
<td><%= booking.user_full_name %></td>
如果用户 nil
此函数将 return 优雅地 return nil 而不会抱怨没有用户。
委托方法调用总是更好(不要指 delegate
作为关键字)而不是调用这么多点,以 booking.showing.film.title
为例,有很多东西这可能会出错,如果预订或放映或电影更改了任何属性,您需要不断迭代所有视图并每次修复每一个视图,而不是尝试创建一个集中函数,例如 booking.film_title
,那么你只需要在一个地方维护它。