通过关联访问数据

时间:2013-01-24 20:13:15

标签: ruby ruby-on-rails-3 associations model-associations

当涉及到RoR时,我非常环保,并且无法弄清楚我的问题是否是由我的模型关联中的问题引起的,或者我是否只是使用正确的语法来访问数据。 / p>

用户可以有很多预算。每个预算由多个细节线组成。我认为budget_details中不需要用户ID,因为它是在预算中捕获的,因此可以通过三者之间的关系推断出来(可能是?!)

在budget_details索引中,我希望能够包含用户名;我已经让它在'show'视图中​​工作,但不是索引。

我确实使用了一个脚手架来设置它们,所以我知道那里有很多不好的东西,我只是想在做一个新的项目之前做一个例子来实现它。

实际错误是;

NoMethodError in Budget_details#index

Showing C:/Sites/example1/app/views/budget_details/index.html.erb where line #17 raised:

undefined method `name' for nil:NilClass

我不明白为什么这会失败但show方法有效?是否与范围有关?即show是单实例级别而index是'all'级别,因此无法在Users中找到数据?

任何帮助非常感谢

型号:

User.rb

class User < ActiveRecord::Base
attr_accessible :email, :name

has_many :budgets
has_many :budget_details, :through => :budgets

Budget.rb

class Budget < ActiveRecord::Base
attr_accessible :budget_name, :user_id

belongs_to :user
has_many :budget_details

Budget_details.rb

class BudgetDetail < ActiveRecord::Base
attr_accessible :amount, :amount_type, :budget_id, :itemname

belongs_to :budget

Controller - budget_details_controller.rb

class BudgetDetailsController < ApplicationController
# GET /budget_details
# GET /budget_details.json
def index
  @budget_details = BudgetDetail.all
  @users = User.all

    respond_to do |format|
    format.html # index.html.erb
    format.json { render json: @budget_details }
  end
end

# GET /budget_details/1
# GET /budget_details/1.json
def show
  @budget_detail = BudgetDetail.find(params[:id])
  @user = User.find(params[:id])

  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @budget_detail }
  end
end
.....

show.html.erb     &lt;%= notice%&gt;

<p>
  <b>Username:</b>
  <%= @user.name %>
</p>

<p>
  <b>Budget:</b>
  <%= @budget_detail.budget_id %>
</p>

<p>
  <b>Itemname:</b>
  <%= @budget_detail.itemname %>
</p>

<p>
  <b>Amount:</b>
  <%= @budget_detail.amount %>
</p>

<p>
  <b>Amount type:</b>
  <%= @budget_detail.amount_type %>
</p>
<%= link_to 'Edit', edit_budget_detail_path(@budget_detail) %> |
<%= link_to 'Back', budget_details_path %>

index.html.erb

<h1>Listing budget_details</h1>

<table>
  <tr>
    <th>Username</th>
    <th>Itemname</th>
    <th>Budget</th>
    <th>Amount</th>
    <th>Amount type</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

<% @budget_details.each do |budget_detail| %>
  <tr>
    <td><%= @user.name %></td>
    <td><%= budget_detail.itemname %></td>
    <td><%= budget_detail.budget_id %></td>
    <td><%= budget_detail.amount %></td>
    <td><%= budget_detail.amount_type %></td>
    <td><%= link_to 'Show', budget_detail %></td>
    <td><%= link_to 'Edit', edit_budget_detail_path(budget_detail) %></td>
    <td><%= link_to 'Destroy', budget_detail, method: :delete, data: { confirm: 'Are    you sure?' } %></td>
  </tr>
<% end %>
</table>

<br />

2 个答案:

答案 0 :(得分:1)

index.html.erb文件中:

<td><%= @user.name %></td>

您尚未在@user操作中定义index - 因此错误。

如果只使用关联,你可以避免这个问题并完全直接拉动控制器中的@user进行任何操作:

<td><%= budget_detail.user.name %></td>

为了避免这样做(N + 1),您可以使用includes在控制器中急切加载它们:

@budget_details = BudgetDetail.includes(:user).all

但是,此关联尚不存在 - 您需要为BudgetDetail课程添加“一对一”关系 - 与您为User课程所做的相反

has_one :user, :through => :budget

总结

您应该将user关联添加到BudgetDetail作为'has-one-through'。

您的控制器操作应如下所示:

def index
  @budget_details = BudgetDetail.includes(:user).all

  respond_to do |format|
    format.html # index.html.erb
    format.json { render json: @budget_details }
  end
end

def show
  @budget_detail = BudgetDetail.find(params[:id])

  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @budget_detail }
  end
end

在您的观看中,不要使用@user.name而是:

<%= budget_detail.user.name %>

答案 1 :(得分:1)

错误表示@user.name错误,因为@user为零。

在您的控制器中,您目前似乎在抓取:

def index
  @budget_details = BudgetDetail.all
  @users = User.all 
end    

def show
  @budget_detail = BudgetDetail.find(params[:id])
  @user = User.find(params[:id]) # THIS WOULD MEAN THAT A USER HAS THE SAME ID AS THE BUDGET_DETAIL
end

当索引操作获取索引模板的变量时,您会发现您没有在那里获取任何@user,只是一个包含所有用户的@users变量。

相反,您应该删除两个操作中的用户提取,并通过budget_detail.user关联在视图中提取它们。

def index
  @budget_details = BudgetDetail.all
end    

def show
  @budget_detail = BudgetDetail.find(params[:id])
end

show.html.erb

<p>
  <b>Username:</b>
  <%= @budget_detail.user.name %>
</p>

<% @budget_details.each do |budget_detail| %>
  <tr>
    <td><%= budget_detail.user.name %></td>
    ...
  </tr>
<% end %>