Home > Mobile >  Multiple Checkbox in Ruby
Multiple Checkbox in Ruby

Time:06-17

I'm trying to create an "ingredient" checkbox list derived from my "recipes", I'd like for the values to be saved in the database so that when it's checked and I refresh the page, it still shows as checked.

The error says "uninitialized constant #Class:0x00007f8f2d360830::Parties"

Here's an example of what i am trying to do

Controller:

# parties_controller.rb

def ingredients
  @party = Party.find(params[:party_id])
  @party_recipe = @party.recipes
  @party_recipe.each do |recipe|
  @ingredients = recipe.ingredients
end

The models:

Party model

#party.rb

class Party < ApplicationRecord
  has_many :party_recipes
  has_many :recipes, through: :party_recipes
end

Recipe model

#recipe_ingredient.rb

class RecipeIngredient < ApplicationRecord
 belongs_to :recipe
 belongs_to :ingredient
end

Ingredient model

#ingredient.rb

class Ingredient < ApplicationRecord
 has_many :recipe_ingredients
 has_many :recipes, through: :recipe_ingredients
end

Form:

#ingredients.html.erb

<% form_for "/parties/#{@party.id}/ingredients" do |f| %>
  <% Parties::Recipes::Ingredients.each do |ingredient| %>
    <%= check_box_tag(ingredient) %>
    <%= ingredient %>
  <% end %>
<% end %>

Schema:

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

  create_table "parties", force: :cascade do |t|
    t.string "title"
    t.string "address"
    t.bigint "user_id", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "theme"
    t.date "date"
    t.integer "attendancy"
    t.integer "appetizers"
    t.integer "mains"
    t.integer "desserts"
    t.string "status", default: "pending"
    t.index ["user_id"], name: "index_parties_on_user_id"
  end

  create_table "party_recipes", force: :cascade do |t|
    t.bigint "recipe_id", null: false
    t.bigint "party_id", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["party_id"], name: "index_party_recipes_on_party_id"
    t.index ["recipe_id"], name: "index_party_recipes_on_recipe_id"
  end

  create_table "recipe_ingredients", force: :cascade do |t|
    t.bigint "recipe_id", null: false
    t.bigint "ingredient_id", null: false
    t.string "amount"
    t.boolean "included", default: false
    t.index ["ingredient_id"], name: "index_recipe_ingredients_on_ingredient_id"
    t.index ["recipe_id"], name: "index_recipe_ingredients_on_recipe_id"
  end

  create_table "recipes", force: :cascade do |t|
    t.string "title"
    t.text "description"
  end

add_foreign_key "party_recipes", "parties"
add_foreign_key "party_recipes", "recipes"
add_foreign_key "recipe_ingredients", "ingredients"
add_foreign_key "recipe_ingredients", "recipes"

I'm not entirely sure where exactly needs to be corrected, any help appreciated, thank you so much!

CodePudding user response:

Well the error message is correct, you don't have any model called Parties, in fact in Rails, models are always singular, camel-case. So that explains the error message.

However that won't fix your problem! The iterator in the view should be

  <% @ingredients.each do |ingredient| %>
    <%= check_box_tag(ingredient) %>
    <%= ingredient %>
  <% end %>

Because I think you are trying to populate an @ingredients variable in your controller. However it still won't work, b/c the value of the @ingredients variable is not being correctly assigned...

Personally I much prefer the "fat model skinny controller" design style for Rails. So I would have a PartiesController#ingredients method that looks like this:

# parties_controller.rb

def ingredients
  @party = Party.find(params[:party_id])
  @ingredients = @party.ingredients
end

then in your Party model:

# app/models/party.rb

  def ingredients
    recipes.map(&:ingredients).flatten
  end

Why do it this way? Well you're just getting started with Rails, but eventually (soon hopefully) you'll be writing tests, and it's much much easier to write tests on models than controllers.

Now, there could well be some other issues in your code, but try my suggestions and see where that gets you.

CodePudding user response:

@Les Nightingill's answer should work well for organizing your controller and model! Regarding when you click refresh and the value of the boxes are saved either;

  1. Set up some listeners in javascript and send a request to your update controller method every time there is a value change for one of your check boxes.

  2. Or add a save button at the bottom of your form that points to your update controller method to save the values of the checkboxes. Something like:

<%= submit_tag "Save", data: { disable_with: "Saving..." } %>

https://api.rubyonrails.org/v5.2.3/classes/ActionView/Helpers/FormTagHelper.html#method-i-submit_tag

  • Related