I'm stuck with this issue.
The RoR doc about this topic is really awful.
I don't understand how collection_select works.
I have two models : Skills and Projects.
A Project have many skills and a skill have many projects.
So here are my schemas :
create_table "projects", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "projects_skills", id: false, force: true do |t|
t.integer "project_id"
t.integer "skill_id"
end
create_table "skills", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "mastering"
end
The Project Model
class Project < ActiveRecord::Base
has_and_belongs_to_many :skills
end
The Skill Model
class Skill < ActiveRecord::Base
has_and_belongs_to_many :projects
end
And the collection_select
= form_for(instance_variable_get('#' + controller.controller_name.singularize)) do |f|
.field
= f.label :skills
= collection_select(:skills, :id, Skill.all, :id, :name, {:multiple=>true})
.actions
= f.submit
The select appears well populated, but nothing is persisted in my database.
Maybe someone can see a mistake in my code ?
Thanks
Related
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!
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.
#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;
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.
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
So I am new to Rails and I have been trying to build a nested form. I have been having a lot of trouble and can't seem to get it to work.. I have watched multiple videos on youtube but I can't seem to find what I am doing different. For the purpose of me trying to build one, I have a Product which has many Buyers but a Buyer belongs to only one Product. (Assume you can only buy one Product...). When I submit my form I get an error which I can see in the server log: "Unpermitted parameter: buyer" I feel like I have tried everything.. I'd be so happy if someone could maybe tell me whats going on. Thanks so much
I have followed the Rails guide and added the following to my models:
class Product < ActiveRecord::Base
has_many :orders
has_many :buyers
accepts_nested_attributes_for :buyers
end
class Buyer < ActiveRecord::Base
belongs_to :product
end
Strong Params in the Product Controller:
def product_params
params.require(:product).permit(:name, :description, :image_url, :color, :adult, buyers_attributes: [:name, :age, :product_id])
end
And the Products controller:
def new
#product = Product.new
#product.buyers.build end
Then for the form:
Form
(Sorry, was having major issues inserting the code here)
Lastly this my schema for both tables:
create_table "buyers", force: :cascade do |t|
t.string "name"
t.integer "age"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "product_id" end
`
create_table "products", force: :cascade do |t|
t.string "name"
t.text "description"
t.string "image_url"
t.string "color"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "price"
t.binary "adult"
end
Your product acceptes nested attributes for buyers but you're only adding buyer (no plural) attributes to the form. You probably need to change the nested form to
<%= f.fields_for :buyers, [#product.buyers.build] do |x| %>
I have two models:
class Order < ActiveRecord::Base
belongs_to :user
has_one :order_type
end
class OrderType < ActiveRecord::Base
belongs_to :order
end
my schema.rb:
create_table "order_types", force: :cascade do |t|
t.string "ort_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "orders", force: :cascade do |t|
t.string "ord_name"
t.date "ord_due_date"
t.integer "user_id"
t.integer "ordertype_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "orders", ["ordertype_id"], name: "index_orders_on_ordertype_id"
add_index "orders", ["user_id"], name: "index_orders_on_user_id"
There is only one-direction association between them. The Order model has a column "ordertype_id" that links to the appropriate order_type.
My question is, what is the best practice to access the ort_name value for each #order in a view.
Currently, I am using:
<p>
<strong>Ord type:</strong>
<% OrderType.where(id: #order.ordertype_id).each do |t| %>
<%= t.ort_name %>
<% end %>
</p>
This solution results in many code repetitions. How I should change that? Can somebody advise, as I am not so experienced yet?
I tried this code, but it did not work:
#orders.order_type
There are many problems which you should address. It's ok to be a beginner, just take yourself time to learn and improve.
Schema
First off, your schema is set up badly. If you want to limit the order type to certain values, you should do this with a validation.
class Order
TYPES = %w[foo bar three four five]
validates :order_type, inclusion: { in: TYPES }
end
This way, you can easily add values in the future, and remove the complexity of adding a new model and its relations.
Column Names
Secondly, you should revise your column names. ord_name and ord_due_date is bad, it leads to ugly calls like order.ord_name. You should drop the prefix ord, it's superfluous.
Both steps would lead to this schema.rb
create_table "orders", force: :cascade do |t|
t.string "name"
t.date "due_date"
t.integer "user_id"
t.string "order_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Logic placement
My final advice is to never call queries from your view. Logic should always be in the controller / model & passed to the view via instance variables.
This is a big no no in rails:
<% OrderType.where(id: #order.ordertype_id).each do |t| %>
...
<% end %>
In the end, accessing the type is simply accomplished with:
#order.order_type
Update your Order model to this:
class Order < ActiveRecord::Base
belongs_to :user
has_one :order_type, foreign_key: 'ordertype_id`
end
then order_type should be easily accessible:
#order.order_type.ort_name
I have a Company that has many Users through a join table company_user. Each user should work for only one Company. This is a 1 to many relationship.
I have looked around for this and found the solution in https://stackoverflow.com/a/7080017/883102
But I get the error
PG::UndefinedTable: ERROR: relation "companies" does not exist
LINE 5: WHERE a.attrelid = '"companies"'::regclass
When I try to create a Company. How can I solve this?
My models are
Company
class Company < ActiveRecord::Base
has_many :employments
has_many :users, :through => :employments
end
Users
class User < ActiveRecord::Base
...
end
Employment
class Employment < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
The migration for my join table is
create_table :employment do |t|
t.belongs_to :company
t.belongs_to :user
t.timestamps
end
My schema.rb
create_table "company", force: true do |t|
t.integer "rating"
t.integer "phone"
t.string "name"
t.string "address"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "employment", id: false, force: true do |t|
t.integer "company_id"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "password_digest"
t.string "remember_token"
t.string "role"
end
Hi I found the answer here
https://stackoverflow.com/a/24318236/883102
The problem was that my table names were in the singular form, I changed these in the migration and then re-created the database. It all seems to be working fine now.
My User class ended up as
class User < ActiveRecord::Base
has_one :employment
has_one :company, :through => :employment
end
This was to allow bi-directional associations
i have a (hopefully) simple question that might have been answered before.. i just couldnt find it... well, here we go, should be easy enough.
I have this schema
create_table "items", :force => true do |t|
t.text "description"
t.string "priority"
t.date "date"
t.time "time"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "done"
t.integer "user_id"
end
create_table "users", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
And I have this in my form for adding a new item:
<%= collection_select(:item, :user_id, User.all, :id, :name) %>
Now, it works, data is saved correctly (I already set up the proper correlations). What i want though, is to display in the items index, the name of the person the item is assigned to, instead of just an ID number.
In items/index I have:
<td><%= item.user_id. %></td>
but i rather want something like
item.user.name
only, it won't work - I guess I need some action in my controller.
Can you help me please? :)
EDIT here is some more details:
My models:
class User < ActiveRecord::Base
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :user
end
Add this to your Items class:
class Items < ActiveRecord::Base
belongs_to :user
end
Then item.user.name should work.