Rails - Form HABTM - ruby-on-rails

I am new to Rails but I am stuck. I would like to create a form that will add data to two tables (books and books_authors). My view looks like:
<%= form_for :book, url: book_path do |f| %>
<p>
<%= f.label :title %> :<br/>
<%= f.text_field :title %><br/>
<ul>
<% #authors.each do |x| %>
<li> <%= f.check_box {...} %> <%= x.name + " " + x.surname%></li>
<% end %>
</ul>
</p>
<p><%= f.submit %></p>
and my create method in controller books_controller.rb looks like:
def create
#book = Book.new(params.require(:book).permit(:title))
#book.save
params[:authors].each do |author_id|
book.authors << Author.find(author_id)
end
redirect_to root_path
end
and my schema:
ActiveRecord::Schema.define(version: 20150709110928) do
create_table "author_books", id: false, force: :cascade do |t|
t.integer "author_id"
t.integer "book_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "author_books", ["author_id"], name:
"index_author_books_on_author_id"
add_index "author_books", ["book_id"],
name:"index_author_books_on_book_id"
create_table "authors", force: :cascade do |t|
t.string "name"
t.string "surname"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "books", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
I need params for :authors but I dont know how to nest it inside the form

I n your _form
<% #authors.each do |author| %>
<%= check_box_tag "author_ids[]", author.id %>
<%= author.name %> // I assume that your author has a name which can be used as a label
<% end %>
in your controller,
def create
// you will get the authors in params[:author_ids]
#book = Book.new(params.require(:book).permit(:title, :author_ids => [])) // its a dirty code
// skip other codes
end
fresh code for controller
define a private method and put
def book_params
params.require(:book).permit(:title, :author_ids => [])
end
and in
def create
#book = Book.new(book_params)
end

Related

How to fixed the value in input field and also set default zero

now i doing a form that can add product to outlet.This form is create at the outletproduct page
So when i click to a product info page have a button (add product to outlet) then go to the form which located at outletproduct page. Now i need to set these things
1.I have create the form out but at the product name field there i need to display product name i choose to be fixed and cannot be change.(Example, click on the product fish then click button then the product name should be fish.)
2.The selling_price and last_cost will need to show the product price and cost in the input field there but this can be change(Example, at product page price is $2 and cost is $1, then here the input field will be selling_price $2 and last_cost $1.)
i have try do but it won't work.
I have update some pic about UI.
OutletProduct Controller
class OutletProductsController < ApplicationController
def new
#outlet_product = OutletProduct.new
#product = Product.all
#outlet = Outlet.all
#category = Category.all
end
def index
end
def show
end
def create
#outlet_product = OutletProduct.new(outlet_product_params)
#category_id = Category.all
#outlet_id = Outlet.all
#product_id = Product.all
if #outlet_product.save
flash[:success] = "Succesful create!"
redirect_to #outlet_product
else
render 'new'
end
end
def edit
end
def outlet_product_params
params.require(:outlet_product).permit(:product_id, :outlet_id, :quantity,
:selling_price ,:last_cost)
end
end
new.html.erb
<h1>Add product to outlet</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: #outlet_product, local: true) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :product_name %>
<%= f.text_field :#product.name ,class: "form-select" %>
<%= f.label :quantity %>
<%= f.number_field :quantity%>
<%= f.label :selling_price %>
<%= f.number_field :selling_price, #product.price , class: 'form-control' %>
<%= f.label :last_cost %>
<%= f.number_field :last_cost,#product.cost, class: 'form-control' %>
<%= f.label :outlet_id %>
<%= f.select(:outlet_id, Outlet.all.collect { |l| [ l.name, l.id] }, {class: "form-select"}) %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
OutletProduct migration in schema
create_table "outlet_products", force: :cascade do |t|
t.integer "outlet_id"
t.integer "product_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.decimal "selling_price"
t.decimal "last_cost"
t.decimal "quantity"
end
product migration in schema
create_table "products", force: :cascade do |t|
t.string "name"
t.integer "quantity"
t.integer "price"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.decimal "cost"
end
Product page
Product info page]
form page
Hi you can define all the default values in view like below
<%= f.label :selling_price %>
<%= f.number_field :selling_price, 0 , class: 'form-control' %>
or if you wanted to keep it by default in the database, then you can make changes in migration files as below:
create_table "products", force: :cascade do |t|
t.string "name", default: 'fish'
t.integer "quantity", default: 0
t.integer "price"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.decimal "cost"
end
I hope this is what you are trying to achieve.

getting "ActionController::ParameterMissing in HomepageController#newbands"

I am trying to print out a form using the simple_form gem but I am getting this error:
ActionController::ParameterMissing in HomepageController#newbands
param is missing or the value is empty: band
homepage_controller.rb
class HomepageController < ApplicationController
def index
end
def bands
end
def newbands
#band = Band.new
#band = Band.create(band_params)
if #band.save
redirect_to "/newbands"
else
render "/"
end
end
private
def band_params
params.require(:band).permit(:name, :country, :members, :genre)
end
end
newbands.html.erb
<%= simple_form_for #band do |b| %>
<%= b.input :name %>
<%= b.input :country %>
<%= b.input :members %>
<%= b.input :genre %>
<%= b.button :submit %>
<% end %>
schema.rb
ActiveRecord::Schema[7.0].define(version: 2022_03_14_133839) do
create_table "bands", force: :cascade do |t|
t.string "name"
t.string "country"
t.integer "members"
t.string "genre"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end

RAILS - User has more than one category

I have a rails app that I'm trying to make an association with USERS (there are many) and Categories (there are 3, which I seeded). Each category has a name and an ID...
When I try to get users to edit their category, the form comes up blank.
The code I'm using for users to select their category is as follows :
<%= form_for (#user) do |f| %>
<%= f.select :categories, #user.categories.all, {multiple: true} %>
(i have also tried Category.all.collect)
Here is what my SCHEMA looks like
create_table "categories", force: :cascade do |t|
t.string "catname"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["user_id"], name: "index_categories_on_user_id"
end
create_table "specialties", force: :cascade do |t|
t.string "specname"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.integer "category_id"
and here are my Models,
class User < ApplicationRecord
has_many :categories
class Category < ApplicationRecord
validates :catname, presence: true
has_many :specialties
belongs_to :user
You can try something like that.
<%= hidden_field_tag "user[category_ids][]", nil %>
<% Category.all.each do |category| %>
<%= check_box_tag "user[category_ids][]", category.id, #user.category_ids.include?(category.id), id: dom_id(category) %>
<%= label_tag dom_id(category), category.catname %> <br>
<% end %>
or
create a field categories in user, then:
<%= form.select :categories, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true%>

How to show the name of category instead of its ID?

I am trying to have the category name show up in the Post's show.html.erb.
This is the current code for it:
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Text:</strong>
<%= #post.text %>
</p>
<p>
<strong>Category:</strong>
<%= #post.category_id %>
</p>
<h2>Comments</h2>
<%= render #post.comments %>
<h2>Add a comment</h2>
<%= render 'comments/form' %>
<%= link_to 'Back', posts_path %>
How do I deal with this part: <%= #post.category_id %> so it can show the name of the category instead?
The current schema is:
create_table "categories", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "comments", force: :cascade do |t|
t.string "name"
t.text "body"
t.integer "post_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["post_id"], name: "index_comments_on_post_id", using: :btree
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "text"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
t.index ["category_id"], name: "index_posts_on_category_id", using: :btree
end
add_foreign_key "comments", "posts"
add_foreign_key "posts", "categories"
end
Current models are:
Post:
class Post < ApplicationRecord
has_many :comments
belongs_to :category
validates :title, presence: true
validates :text, presence: true
end
Categories:
class Category < ApplicationRecord
has_many :posts
end
Comment:
class Comment < ApplicationRecord
belongs_to :post
end
You should access #post's category's name:
#post.category.name
Because you are using association belongs_to in Post model, you can get the category name in your view this way:
<%= #post.category.name %>

Rails comments do not save

Edit: Log from form submission:
Started POST "/posts/1/comments" for 141.161.133.10 at 2015-03-19 17:10:19 +0000
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"9laIJxseq/x+7C3iJAdpvalFvMgN397lWC7c/6Ha/hEjKTE9A3e19liFlwGzZjePReFdh2F1fLj1itZzRjixgQ==", "comment"=>{"body"=>"Hi stackoverflow"}, "commit"=>"Submit", "post_id"=>"1"}
(0.3ms) begin transaction
SQL (1.9ms) INSERT INTO "comments" ("body", "created_at", "updated_at") VALUES (?, ?, ?) [["body", "Hi stackoverflow"], ["created_at", "2015-03-19 17:10:19.808006"], ["updated_at", "2015-03-19 17:10:19.808006"]]
(32.1ms) commit transaction
Redirected to https://blog-erikvdw.c9.io/posts.10
Completed 302 Found in 48ms (ActiveRecord: 34.2ms)
And comment_params method:
def comment_params
params.require(:comment).permit(:body)
end
I've looked around quite a while in a github repo and other SO questions similar to what I am doing, but haven't seen exactly what I'm doing wrong. My problem is that comments are not being created when the comments form is submitted in Posts/Show. I presume it to be an issue with an activerecord association:
Posts/Show
<% content_for(:title, #post.title ) %>
<p id="notice"><%= notice %></p>
<h1>Blog</h1>
<br>
<div>
<%= image_tag #post.image.full.url %>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2><em><%= #post.title %></em></h2>
</div>
<div class="panel-body">
<p><%= #post.content %></p>
</div>
</div>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Back', posts_path %>
<% #post.comments.each do |comment| %>
<%= comment.body %>
<% end %>
<%= form_for [#post, #post.comments.build] do |f| %>
<%= f.text_area :body %>
<%= f.submit "Submit" %>
<% end %>
<p>Comments: <%= #post.comments.count %></p>
Posts Model
class Post < ActiveRecord::Base
has_many :comments, dependent: :destroy
mount_uploader :image, PostUploader
end
Comments Model
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
Schema File
create_table "comments", force: :cascade do |t|
t.string "body"
t.integer "user_id"
t.integer "employee_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_id"
end
add_index "comments", ["employee_id"], name: "index_comments_on_employee_id"
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image"
end
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "username"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
Comments_Controller New and Create Actions
def new
#comment = Comment.new
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to posts_path(#comment), notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
You're not creating the Comment through the specific Post, so no association is being made. Try this in your create action:
#comment = Post.find(params[:post_id]).comments.new(comment_params)
This will populate the post_id in your comments table automatically which will then link it to the Post.

Resources