【问题标题】:How can I set my controller and views when I have two Many-to-Many association?当我有两个多对多关联时,如何设置我的控制器和视图?
【发布时间】:2018-11-07 15:54:58
【问题描述】:

我的目标是按类别组织上传的帖子。这些类别显示在导航栏上,如果您单击类别名称之一,您将看到分配有该类别的帖子。上传帖子时,您也可以为其分配多个类别。所以,我认为这就像很多帖子可以有很多类别,很多类别可以有很多帖子。

This is how I want my posts organized by categories

但是,我无法在我的 posts_controller.rb、posts/index.html.erb、posts/show.html.erb 和 _navigation.html.erb 中设置正确

post.rb

class Post < ActiveRecord::Base
  #This validates presence of title, and makes sure that the length is not more than 140 words
  validates :title, presence: true, length: {maximum: 140}
  #This validates presence of body
  validates :body, presence: true
    has_many :categorizations
    has_many :categories, :through => :categorizations 
end

category.rb

class Category < ApplicationRecord
    has_many :categorizations
    has_many :posts, :through => :categorizations
end

分类.rb

class Categorization < ApplicationRecord
    belongs_to :post
    belongs_to :category
end

然后,这些控制器和视图让我感到困惑:

posts_controller.rb

class PostsController < ApplicationController
  before_action :find_post, only: [:edit, :update, :show, :delete]
  before_action :authenticate_admin!, except: [:index, :show]
  # Index action to render all posts
  def index
    if params.has_key?(:category)
    @category = Category.find_by_name(params[:category])
    @posts = Post.where(category: @category)
    else
    @posts = Post.all
    end
  end

  # New action for creating post
  def new
    @post = Post.new
  end

  # Create action saves the post into database
  def create
    @post = Post.new(post_params)
    if @post.save
      flash[:notice] = "Successfully created post!"
      redirect_to post_path(@post)
    else
      flash[:alert] = "Error creating new post!"
      render :new
    end
  end

  # Edit action retrives the post and renders the edit page
  def edit
  end

  # Update action updates the post with the new information
  def update
    @post = Post.find(params[:id])
    if @post.update_attributes(post_params)
      flash[:notice] = "Successfully updated post!"
      redirect_to posts_path(@posts)
    else
      flash[:alert] = "Error updating post!"
      render :edit
    end
  end

  # The show action renders the individual post after retrieving the the id
  def show 
  end


  # The destroy action removes the post permanently from the database
  def destroy
    @post = Post.find(params[:id])
    if @post.present?
       @post.destroy
      flash[:notice] = "Successfully deleted post!"
      redirect_to posts_path
    else
      flash[:alert] = "Error updating post!"
    end
  end

  private

  def post_params
    params.require(:post).permit(:title, :body, category_ids: [])
  end

  def find_post
    @post = Post.find(params[:id])
  end
end

index.html.erb

<div class="container">
  <div class="col-sm-10 col-sm-offset-1 col-xs-12">
    <% @posts.each do |post| %>
    <div class="col-xs-12 text-center">
      <div class="text-center">
        <h2><%= post.title %></h2>
        <h6><%= post.created_at.strftime('%b %d, %Y') %></h6>
      </div>
      <div>
        <%= raw post.body.truncate(358) %>
      </div>
      <div class="text-center">
        <%= link_to "READ MORE", post_path(post) %>
      </div>
      <% if admin_signed_in? %>
        <%= link_to "Show", post_path(post), class: "btn btn-primary" %>
        <%= link_to "Edit", edit_post_path(post), class: "btn btn-default" %>
        <%= link_to "Delete", post_path(post), class: "btn btn-danger", data: {:confirm => "Are you sure?"}, method: :delete %>
      <% end %>
      <hr />
    </div>
    <% end %>
  </div>
</div>

show.html.erb

<div class="col-sm-11 col-xs-12 blog-content">
  <h2 class="text-center"><%= @post.title %></h2>
  <h1 class="text-center"><%= @category.name %></h1>
  <h5 class="text-center"><%= @post.created_at.strftime('%b %d, %Y') %></h5>
  <div class="text-center"><%= raw @post.body %></div>
</div>

_navigation.html.erb(部分)

   <ul class="nav navbar-nav navbar-left">
    <% Category.all.each do |cat|  %>
    <li class="text-center"><%= link_to cat.name, posts_path(category: cat.name) %></li>
    <% end %>
   </ul>

以防万一,schema.rb

ActiveRecord::Schema.define(version: 2018_11_07_082317) do

  create_table "admins", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "avatar"
    t.index ["email"], name: "index_admins_on_email", unique: true
    t.index ["reset_password_token"], name: "index_admins_on_reset_password_token", unique: true
  end

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

  create_table "categories_posts", id: false, force: :cascade do |t|
    t.integer "category_id"
    t.integer "post_id"
  end

  create_table "categorizations", force: :cascade do |t|
    t.integer "post_id"
    t.integer "category_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "ckeditor_assets", force: :cascade do |t|
    t.string "data_file_name", null: false
    t.string "data_content_type"
    t.integer "data_file_size"
    t.string "type", limit: 30
    t.integer "width"
    t.integer "height"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["type"], name: "index_ckeditor_assets_on_type"
  end

  create_table "posts", force: :cascade do |t|
    t.string "title"
    t.text "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

【问题讨论】:

  • 索引、显示视图和导航栏有哪些特殊问题?你想达到什么目标?
  • 感谢您修复我的节目视图。这就是我想要的。另外,我想实现按类别对帖子进行排序。因此,如果您单击导航栏上的类别名称,您将看到该类别中的所有帖子。

标签: ruby-on-rails many-to-many blogs categories


【解决方案1】:

在显示视图中你有

<h1 class="text-center"><%= @category.name %></h1>

但是你没有在 show action 中定义@category。如果要列出类别,应该是

<h1 class="text-center"><%= @post.categories.pluck(:name).join(', ') %></h1>

顺便说一句,看起来你在 schema.rb 中有无用的表 categories_posts

更新:

关于索引操作 - 您应该更改@posts 的查询,因为帖子没有类别列,但他有categories 关联:

def index
  if params.has_key?(:category)
    # you can remove @category defining if you don't need it somewhere in view
    @category = Category.find_by_name(params[:category])
    @posts = Post.joins(:categories).where(categories: { name: params[:category] } )
  else
    @posts = Post.all
  end
end

注意,查询时最好使用 id,而不是 name,通过 id 搜索更快。您需要将导航栏中的链接更改为link_to cat.name, posts_path(category: cat.id),并在查询中将name 替换为id。并且最好将整个查询移动到 Post 模型中的命名范围。

【讨论】:

  • 谢谢,我现在可以在帖子中显示类别了。
  • 所以,我仍然想以一种可以通过单击导航栏上的类别名称访问某些类别帖子的方式来组织帖子。您是否知道哪里出了问题,因为当我单击导航栏上的类别时出现此错误。
  • ActiveRecord::StatementInvalid in Posts#index Showing /home/ec2-user/environment/AIU-Blog/app/views/posts/index.html.erb where line #3 raise: SQLite3:: SQLException:没有这样的列:posts.category: SELECT "posts".* FROM "posts" WHERE "posts"."category" = ?提取的源代码(第 3 行附近):

  • 非常感谢!一切都解决了。所以,最后一个问题。删除 categories_posts 表不会影响任何事情吗?我想我有分类表,可以吗?
  • @KoutaNakano,很高兴为您提供帮助 :) 如果您放下桌子应该没问题。我认为以前您在帖子和类别之间有have_and_belongs_to_many 关联?由于您将其更改为has_many :categories, :through =&gt; :categorizations,因此您不再需要旧表
猜你喜欢
相关资源
最近更新 更多
热门标签