代码之家  ›  专栏  ›  技术社区  ›  stephenmurdoch

HABTM关系并接受

  •  4
  • stephenmurdoch  · 技术社区  · 14 年前

    我有一个表单让我创建 新博客文章 新类别 同样的形式。

    我有一个职位和类别之间的habtm关系,这就是为什么我有这个麻烦。

    我有以下两种型号:

    class Post < ActiveRecord::Base
      has_and_belongs_to_many :categories
      attr_accessible :title, :body, :category_ids
    
      accepts_nested_attributes_for :categories # should this be singular? 
    end
    
    class Category < ActiveRecord::Base
      has_and_belongs_to_many :posts
      attr_accessible :name
    end
    

    我的表单允许我从一堆现有的类别中选择或创建一个全新的类别。我的表格如下。

    # using simple_form gem
    .inputs
      = f.input :title
      = f.input :body
    
      # the line below lets me choose from existing categories
      = f.association :categories, :label => 'Filed Under'
    
      # I was hoping that the code below would let me create new categories
      = f.fields_for :category do |builder|
        = builder.label :content, "Name"
        = builder.text_field :content
    

    当我提交表单时,它会被处理,但不会创建新类别。我的命令提示符输出告诉我:

    WARNING: Can't mass-assign protected attributes: category
    

    但是,如果我加上 attr_accessible :category ,我得到一个大的fat崩溃,错误消息是“未知属性:类别”。

    我花了一段时间试图解决这个问题,并观看了最近的嵌套模型和简单表单上的railscasts,但无法解决我的问题。

    如果我使用hasúu many:through relationship(使用连接模型)而不是habtm,这会更容易吗?

    4 回复  |  直到 14 年前
        1
  •  1
  •   stephenmurdoch    14 年前

    感谢所有回答的人。经过反复试验,我终于想出了一个解决办法。

    首先,我从HABTM换成了 有很多:通过 关系,调用我的加入模型 (而不是分类_posts.rb)-注意:下面详细介绍的修复程序也可能适用于HABTM:

    # post.rb
    class Post < ActiveRecord::Base
      has_many :categorizations
      has_many :categories, :through => :categorizations
      attr_accessible :title, :body, :category_ids
      accepts_nested_attributes_for :categories
    end
    
    #category.rb
    class Category < ActiveRecord::Base
      has_many :categorizations
      has_many :posts, :through => :categorizations
      attr_accessible :name, :post_ids
    end
    
    #categorization.rb
    class Categorization < ActiveRecord::Base
      belongs_to :post
      belongs_to :category
    end
    

    从上面的post模型来看:显然,访问器名为 如果要启用选择多个 现有类别 不要 需要访问器方法 新类别。。。我不知道。

    第二步:我把我的观点改成这样:

    -# just showing the relevent parts
    = fields_for :category do |builder|
      = builder.label :name, "Name"
      = builder.text_field :name
    

    从上面的视图代码中,注意使用 fields_for :category 与有些不真实的 fields_for :categories_attributes

    步骤3 最后,我给控制器添加了一些代码:

    # POST /posts
    # POST /posts.xml
    def create
      @post = Post.new(params[:post])
      @category = @post.categories.build(params[:category]) unless params[:category][:name].blank?
      # stuff removed
    end
    
    
    def update
      @post = Post.find(params[:id])
      @category = @post.categories.build(params[:category]) unless params[:category][:name].blank?
      # stuff removed
    end
    

    现在,当我创建一个新文章时,我可以同时从选择菜单中选择多个现有类别 同时创建一个全新的类别-这不是一个或另一个的情况

    有一个 哪一个 只有 编辑和更新 现有文章;在这种情况下,我不会同时创建新类别 选择多个现有类别-如果我尝试同时执行这两个操作,则只有现有类别与帖子关联,而全新类别被拒绝(没有错误消息)。 我可以通过编辑这篇文章两次来解决这个问题,一次创建新的类别(自动将其与文章关联),然后第二次从菜单中选择一些其他现有的类别-就像我说的,这不是什么大问题,因为这一切都很好,否则我的用户可以适应这些限制

    不管怎样,我希望这能帮助别人。

        2
  •  0
  •   Yannis    14 年前

    在您的表单中,您可能应该为每个类别呈现一次字段(每个帖子可以有多个类别,因此是habtm关系)。尝试以下方法:

    - for category in @post.categories
      = fields_for "post[categories_attributes][#{category.new_record? ? category.object_id : category.id}]", category do |builder|
        = builder.hidden_field :id unless category.new_record?
        = builder.label :content, "Name"
        = builder.text_field :content
    
        3
  •  0
  •   Dinshaw Raje    11 年前

    我已经提出申请,我的嵌套表格与HABTM合作。

    class UserProfile < ActiveRecord::Base
    
        attr_accessible :name, :profession
    
        has_and_belongs_to_many :cities
    
        belongs_to :user
    
        attr_accessible :city_ids, :cities
        def self.check_city(user,city)
    
         user.cities.find_by_id(city.id).present?
    
        end 
    
    end
    
    class City < ActiveRecord::Base
    
        attr_accessible :city_name
    
        has_and_belongs_to_many :user_profiles
    
    end
    

    以我的形式,我有:

    -# just showing the relevent parts
    
    
    = f.fields_for :cities do|city| 
    
                = city.text_field :city_name 
    

    在我的控制器上:

     def create
    
        params[:user_profile][:city_ids] ||= [] 
        if params[:user_profile][:cities][:city_name].present?
          @city= City.create(:city_name=>params[:user_profile][:cities][:city_name])
          @city.save
          params[:user_profile][:city_ids] << @city.id
        end
    
        @user=current_user
        params[:user_profile].delete(:cities)
        @user_profile = @user.build_user_profile(params[:user_profile])
    
        respond_to do |format|
          if @user_profile.save
    
            format.html { redirect_to @user_profile, notice: 'User profile was successfully created.' }
            format.json { render json: @user_profile, status: :created, location: @user_profile }
          else
            format.html { render action: "new" }
            format.json { render json: @user_profile.errors, status: :unprocessable_entity }
          end
        end
      end
    
    def update
    
        params[:user_profile][:city_ids] ||= [] 
        if params[:user_profile][:cities][:city_name].present?
          @city= City.create(:city_name=>params[:user_profile][:cities][:city_name])
          @city.save
          params[:user_profile][:city_ids] << @city.id
        end
        @user=current_user
        params[:user_profile].delete(:cities)
        @user_profile = @user.user_profile
    
        respond_to do |format|
          if @user_profile.update_attributes(params[:user_profile])
    
            format.html { redirect_to @user_profile, notice: 'User profile was successfully updated.' }
            format.json { head :no_content }
          else
            format.html { render action: "edit" }
            format.json { render json: @user_profile.errors, status: :unprocessable_entity }
          end
        end
      end
    

        4
  •  -1
  •   BvuRVKyUVlViVIc7    14 年前

    也许你应该试试(不是测试者):

    attr_accessible :category_attributes
    

    而且HBTM之间的关系并不是真的被建议。。。但我自己用:P