我在many_to_many
和Categories
之间建立Articles
关联,在Rails 4应用中使用has_and_belongs_to_many
:
以下是相应的迁移和类:
class CategoriesArticles < ActiveRecord::Migration
def change
create_table :categories_articles, id: false do |t|
t.belongs_to :category, index: true
t.belongs_to :article, index: true
end
add_index :categories_articles, [:category_id, :article_id]
end
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :articles
end
class Article < ActiveRecord::Base
has_and_belongs_to_many :categories
end
当用户创建新文章时,我只想让他或她选择他/她想要与新文章关联的类别。我希望用户能够使用复选框选择这些类别。
这里是ArticlesController
:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :destroy, :update]
before_action :verify_own_article, only: [:destroy]
respond_to :html
def index
if user_signed_in?
@articles = current_user.article_feed
# TODO: if there are too few articles on a user's feed, we want to display more articles
else
@articles = Article.all
end
@articles = @articles.page(params[:page] || 1).per(12)
respond_with(@articles)
end
def show
respond_with(@article)
end
def new
@categories = Category.all
@article = Article.new
respond_with(@article)
end
def edit
if current_user.articles.find_by_id(params[:id]).nil?
flash[:notice] = "You do not have permission to edit this article."
redirect_to @article
end
end
def create
# Creates article object with current_user_id, initial_comment, and URL
@article = current_user.articles.build(article_params)
# Uses Pismo (gem) to grab title, content, photo of URL
@article.populate_url_fields
if @article.save
flash[:success] = "Article created!"
# Might need to change the location of this redirect
redirect_to root_url
else
flash[:notice] = "Invalid article."
redirect_to new_article_path
end
end
def update
@article.update(article_params)
flash[:notice] = "Article successfully updated."
respond_with(@article)
end
def destroy
if @article
@article.destroy
flash[:notice] = "Article successfully destroyed."
else
flash[:notice] = "You do not have permission to delete this article."
end
# TODO: change this to another redirect location
redirect_to root_path
end
private
def set_article
@article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:url, :title, :datetime, :content, :photo, :initial_comment)
end
# Ensure that a signed in user can only delete articles that they have posted
def verify_own_article
@article = current_user.articles.find_by_id(params[:id])
end
end
这里是文章new.html.erb
视图:
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
...和form
部分:
<%= form_for(@article) do |f| %>
<% if @article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% @article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :url %><br>
<%= f.text_field :url %>
</div>
<div class="field">
<%= f.label :initial_comment %><br>
<%= f.text_field :initial_comment %>
</div>
<% @categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
然而,这对我来说是错误的,特别是行:
<% @categories.each do |t| %>
<div class="field">
<%= f.label t.name %>
<%= f.check_box "categories[#{t.id}]" %>
<br />
</div>
<% end %>
具体来说,它告诉我:
undefined method 'categories[1]' for #<Article:0x007f401193d520>
。我该如何解决?感谢。
答案 0 :(得分:0)
我注意到您的联接表名为
create_table :categories_articles, id: false do |t|
名称必须按字母顺序排列。
create_table :articles_categories, id: false do |t|
我的选择是Rails无法找到您的联接表。这意味着它调用@ article.categories时的表单无法找到它需要的内容。如果你调用@ category.articles会发生同样的情况(即:能够找到连接表与对象的任意顺序无关)。
请参阅我对this question
的回答