如何在控制器和方法上实现Has Many Through Association

时间:2017-12-26 18:56:32

标签: ruby-on-rails simple-form has-many-through simple-form-for

在我的应用中我在管理员中创建类别(因此管理员创建,更新和销毁类别名称),然后当用户创建帖子时,他们将选择(或者我正在考虑切换复选框)帖子的类别。

我决定在帖子和类别中使用多个for来实现此实现。但是我'怀疑工具:

  1. post_params;
  2. 添加类别然后销毁类别的方法
  3. 以及创建,更新和销毁帖子的部分。
  4. 我该如何实现?做不同的更好的方法是什么?所以如果有人帮助我,我会很感激。

    Post.rb

      class Post < ActiveRecord::Base
           has_many :categorizations
           has_many :categories, through: :categorizations
        ...
          def add_category(category)
            categorizations.create(category_id: category.id)
          end
    
          def remove_category(category)
            categorizations.find_by(category_id: category.id).destroy
          end
    

    category.rb

    class Category < ActiveRecord::Base
      has_many :categorizations
      has_many :posts, through: :categorizations
    
      validates :name,
                      presence: true,
                      length: { minimum: 3, maximum: 30 },
                      uniqueness: true
    end
    

    categorization.rb

    class Categorization < ActiveRecord::Base
      belongs_to :post
      belongs_to :category
    
      validates :post_id, presence: true
      validates :category_id, presence: true
    end
    

    控制器/管理/ PostsController

    class Admin::PostsController < Admin::ApplicationController
      def new
        @post = Post.new
        @categories = Category.all.map{ |c| [c.name, c.id]}
      end
    
      def create
        @post = Post.new(post_params)
        @post.author = current_user
        @post.categories << params[:category_id]
    
        if @post.save
          flash[:notice] = "Post has been created."
          redirect_to @post
        else
          flash[:alert] = "Post has not been created."
          render "new"
        end
      end
    
    
    
      def destroy
        @post = Post.find(params[:id])
        @post.destroy
    
        flash[:notice] = "Post has been deleted."
        redirect_to posts_path
      end
    
      private
    
      def post_params
        params.require(:post).permit(:title,
                                     :subtitle,
                                     :content,
                                     :attachment,
                                     :attachment_cache,
                                     :remote_attachment_url,
                                     :categorizations_attributes => [:id,
                                                                     :post_id,
                                                                     :category_id,
                                                                     :_destroy,
                                                                     :categories_attributes => [:id,
                                                                                                :name]
                                                                    ]
                                     )
      end
    end
    

    控制器/ posts_controller.rb

    class PostsController < ApplicationController
      before_action :set_post, only: [:show, :edit, :update]
    
      def index
        @posts = policy_scope(Post)
      end
    
      def show
        authorize @post, :show?
      end
    
      def edit
        authorize @post, :update?
      end
    
      def update
        authorize @post, :update?
        if @post.update(post_params)
          flash[:notice] = "Post has been updated."
          redirect_to @post
        else
          flash.now[:alert] = "Post has not been updated."
          render "edit"
        end
      end
    
      private
    
      def set_post
        @post = Post.find(params[:id])
      rescue ActiveRecord::RecordNotFound
        flash[:alert] = "The post you were looking for could not be found."
        redirect_to posts_path
      end
    
      def set_category
        @category = Category.find(params[:category_id])
      end
    
      def post_params
        params.require(:post).permit(:title, :subtitle, :content, :attachment, :attachment_cache, :remove_attachment, :remote_attachment_url, :category_id)
      end
    end
    

    文章/ _form.html.slim

    = simple_form_for([:admin, @post], :html => { :multipart => true }) do |f|
       = select_tag(:category_id, options_for_select(@categories), :prompt => "Select ad Category")
    

    路由

     Rails.application.routes.draw do
    
      namespace :admin do
        root 'application#index'
    
        resources :posts, only: [:new, :create, :destroy]
        resources :categories
    
        resources :users do
          member do
            patch :archive
          end
        end
      end
    
      devise_for :users
    
      root "posts#index"
    
      resources :posts, only: [:index, :show, :edit, :update]
    end
    

2 个答案:

答案 0 :(得分:0)

以您的形式

= select_tag(:category_ids, options_for_select(@categories), :prompt => "Select ad Category", multiple: true)

在您的控制器中

params.require(:post).permit(:title, :subtitle, :content, :attachment, :attachment_cache, :remove_attachment, :remote_attachment_url, :category_ids)

还需要在posts_controller.rb中提供一些建议  删除下面的行

rescue ActiveRecord::RecordNotFound

Insterad of this在application_controller.rb中编写它,因此它适用于整个应用程序。

答案 1 :(得分:0)

我为修复做的是把它放在PostsController上:

class Admin::PostsController < Admin::ApplicationController
  before_action :set_categories, only: [:new, :create]
   .
   .
   .
  private

  def set_categories
    @categories = Category.all.select(:id, :name)
  end

  def post_params
    params.require(:post).permit(:title,
                                 :subtitle,
                                 :content,
                                 :attachment,
                                 :attachment_cache,
                                 :remote_attachment_url,
                                 category_ids:[]
                                 )
  end

在表单上我更改了使用复选框,我可以为帖子选择并添加更多类别:

   = f.association :categories, label: "Select the Categories", as: :check_boxes , collection: @categories.map{|c| [c.name, c.id]}, include_hidden: false

添加类Post和Category a dependent: :destroy以正确销毁连接。

has_many :categorizations, dependent: :destroy
has_many :categories, through: :categorizations

并且有必要删除post_id对分类的验证,所以我只是评论,因为当我尝试创建Post时取消注释时,这是不可能的,所以我这样做:

class Categorization < ActiveRecord::Base
  belongs_to :post
  belongs_to :category

  #validates :post_id, presence: true
  validates :category_id, presence: true
end

工作了!