1

I have the following three models with relationships:

# category.rb
class Category < ActiveRecord::Base
  has_many :category_marks
  accepts_nested_attributes_for :category_marks
end

# category_mark.rb
class CategoryMark < ActiveRecord::Base
  attr_accessible: :add, :stu, :inc

  validates_presence_of :user_group
  validates_presence_of :category_id
  belongs_to :category
  belongs_to :user_group
end

# user_group.rb
class UserGroup < ActiveRecord::Base
  has_many :category_marks
end

category_marks describe the access permissions of different user groups to different categories. I'm trying to create the category marks when I create a new category, hence the accepts_nested_attributes_for. I'm able to edit categories and update category_marks at the same time, but not when I'm creating new category. This is my categories_controller.rb (irrelevant bits removed):

class Admin::CategoriesController < ApplicationController

    def new
      @category = Category.new
      @category.category_marks.build(UserGroup.all.map{|ug| { user_group: ug }})

      respond_to do |format|
        format.html # new.html.erb
        format.json { render json: @category }
      end
    end

    def edit
      @category = Category.find(params[:id])
    end

    def create
      @category = Category.new
      @category.category_marks.build(UserGroup.all.map{|ug| { user_group: ug }})
      @category.attributes = params[:category]

      respond_to do |format|
        if @category.save
          format.html { redirect_to [:admin, :categories], notice: 'Category was successfully created.' }
          format.json { render json: @category, status: :created, location: @category }
        else
          format.html { render action: "new" }
          format.json { render json: @category.errors, status: :unprocessable_entity }
        end
      end
    end

    def update
      @category = Category.find(params[:id])

      respond_to do |format|
        if @category.update_attributes(params[:category])
          format.html { redirect_to [:admin, :categories], notice: 'Category was successfully updated.' }
          format.json { head :no_content }
        else
          format.html { render action: "edit" }
          format.json { render json: @category.errors, status: :unprocessable_entity }
        end
      end
    end
  end

Every category needs a category mark for every user group, so in the new action I'm building a category marks object and association for every user group onto my new @category object. This works fine and enables me to display the form fields for each category mark using a nested form. The difficulty I'm now having is getting those category marks to save in the create action.

params comes into create like:

{"utf8"=>"✓",
"authenticity_token"=>"0rNpYy7OB+DPuzmu8HoxX2MvTnkjUyU+Vej+a4RMh7s=",
"category"=>{
  "name"=>"test category",
  "color"=>"#00f",
  "parent_id"=>"3",
  "category_marks_attributes"=>{
    "0"=>{
      "stu"=>"1",
      "inc"=>"0",
      "add"=>"1"},
    "1"=>{
      "stu"=>"0",
      "inc"=>"1",
      "add"=>"1"}}},
"button"=>"",
"action"=>"create",
"controller"=>"admin/categories"}

View code for the form:

<%= form_for([:admin, @category]) do |category_form| %>
  <ul>
    <li><%= category_form.label :name %> <%= category_form.text_field :name %></li>
    <li><%= category_form.label :color %> <%= category_form.text_field :color, class: :add_colour_picker %></li>
    <li><%= category_form.label :parent_id, "Parent category" %> <%= category_form.select :parent_id, Category.roots.delete_if{|c| c == @category}.map{|c| [c.name, c.id]}, include_blank: true %></li>
    <br />
    <h2>User Group Permissions</h2>
    <table>
      <tr>
        <th>User Group</th>
        <th>View Students</th>
        <th>View Incidents</th>
        <th>Add Incidents</th>
      </tr>
      <%= category_form.fields_for :category_marks do |category_marks_form| %>
      <%= category_marks_form.hidden_field :user_group_id, value: category_marks_form.object.user_group_id %>
        <tr>
          <td><%= category_marks_form.object.user_group.name %></td>
          <td><%= category_marks_form.check_box :stu %></td>
          <td><%= category_marks_form.check_box :inc %></td>
          <td><%= category_marks_form.check_box :add %></td>
        </tr>
      <% end %>
    </table>

    <li><%= button_tag "Save Category" %></li>
  </ul>
<% end %>

1 Answer 1

2

Your category_marks_attributes in params are missing the user_group_id and therefore would not validate or save based on the user input.

You probably need to add something like the following to your view:

= category_marks_builder.hidden_field :group_id, value: category_marks_builder.object.group_id

Also, I'm pretty sure it works as you have it, but I would get rid of the @category.attributes= line and call @category.update_attributes params[:category] instead of @category.save.

Lastly, I'm not sure why you're doing the @category.category_marks.build call again in the create controller. I think this is going to give you two sets of category_marks. One with the user inputs and one with default values.

I hope it helps.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for helping! I still can't get it to work, getting the errors: #<ActiveModel::Errors:0x007f8111498790 @base=#<Category id: nil, name: "asd", color: "", created_at: nil, updated_at: nil, medical: false, parent_id: 3, lft: nil, rgt: nil>, @messages={:"category_marks.user_group"=>["can't be blank"], :"category_marks.category"=>["can't be blank"]}>. I've updated my question with the view code.
Does it change anything if you change your validates_presence_of statements to include or exclude the _id suffix? I think you might need user_group_id and category.
Played with various combinations without success but I've taken off _id from the validations and the relationships as I don't think it was necessary and confusing things. I'm only getting the one error now: :"category_marks.category"=>["can't be blank"] - argh! I have tried adding category and category_id to the attr_accessible of CategoryMark, neither solved it.
Ah, hang on a minute, it works perfectly fine if I take out my validates_presense_of :category. Seems like it's checking to see if the category exists before it's even saved the category, hmpf. Now for figuring out how to get around that.
Ah, now I remember. I think you might need an inverse_of statement.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.