Add records using HABTM association - ruby-on-rails

I still new with ruby on rails and I am really blocked.
I am trying to add linked books and authors to database, it add the record in the two tables but not in tne join one. This is my code:
books_controller.rb
class BooksController < ApplicationController
def index
#books= Book.all
end
def new
#book= Book.new
end
def create
#book= Book.new(book_params)
if #book.save
redirect_to books_path
else
redirect_to root_url
end
end
private
def book_params
params.require(:book).permit(:title, {:author_ids =>[]})
end
end
book.rb
class Book < ActiveRecord::Base
has_and_belongs_to_many :authors
before_destroy { authors.clear }
end
author.rb
class Author < ActiveRecord::Base
has_and_belongs_to_many :books
end
books/new.html.erb
<h1>Add new book</h1>
<%= form_for #book do |f| %>
<%= f.label :title %>
<%=f.text_field :title %>
<% for author in Author.all %>
<%= check_box_tag 'book(author_ids[])',author.id, #book.authors.include?(author) %>
<%= author.f_name %>
<% end%>
<%= f.submit %>
<%end%>

Change <%= check_box_tag 'book(author_ids[])',author.id, #book.authors.include?(author) %> into <%= check_box_tag 'book[author_ids][]',author.id, #book.authors.include?(author) %>

Related

Rails 5 Nested forms update not creating new records

I am trying to build a nested form and having issues when using the edit page of the resource. I can get the new action to work fine, but I am finding if I try to update the resource to include new sub-resource it doesn't save the subresources.
I am running rails 5.2 and have cocoon gem installed for the nested forms.
An order has many cards
Order Model:
class Order < ApplicationRecord
has_many :cards, dependent: :destroy
accepts_nested_attributes_for :cards, allow_destroy: true
end
Card Model:
class Card < ApplicationRecord
belongs_to :order
end
Orders Controller:
class OrdersController < ApplicationController
def index
#orders = Order.all
end
def new
#order = Order.new
#order.cards.build
end
def create
#order = Order.new(order_params)
if #order.save
redirect_to order_path(#order)
else
render 'new'
end
end
def show
#order = Order.find(params[:id])
end
def edit
#order = Order.find(params[:id])
#order.cards.build
end
def update
#order = Order.find(params[:id])
if #order.update_attributes(order_params)
redirect_to order_path(#order)
else
render 'edit'
end
end
def destroy
#order = Order.find(params[:id])
#order.destroy
redirect_to orders_path
end
private
def order_params
params.require(:order).permit(:title, :price, cards_attributes: [:id, :title, :price, :_destroy])
end
end
Orders Edit View:
<%= form_for #order do |f| %>
<%= f.fields_for :cards do |card| %>
<%= render 'card_fields', f: card %>
<% end %>
<%= link_to_add_association f, :cards, class: "add-cards" do %>
<span>Add Card</span>
<% end %>
<%= f.submit "Update" %>
<% end %>
Orders form partial View:
<div class="nested-fields">
<%= f.label :title, 'Card Description', class: "g-mb-10" %>
<%= f.text_field :title, class: "form-control form-control-md g-brd-gray-light-v7 g-brd-lightblue-v3--focus g-rounded-4 g-px-20 g-py-12" %>
<%= link_to_remove_association f, class: "remove-quals u-link-v5 d-flex align-items-center g-color-lightblue-v3 g-ml-30" do %>
<span class="g-ml-15">Remove Card</span>
<% end %>
</div>
Now if I add #order.cards.build to the edit action it works, but if no new card is added it still creates an empty record. Also if I change
accepts_nested_attributes_for :cards, allow_destroy: true
to
accepts_nested_attributes_for :cards, allow_destroy: true, reject_if: proc { |attributes| attributes['price'].blank? }
This is works as long as none of the other items are being updated at the same time.
Ideally, When someone goes to edit order a new card shouldn't be visible till someone clicks add card.
Any help would be greatful.
Thanks
found my problem.
Edit view (add div with id of cards)
<%= form_for #order do |f| %>
<div id="cards">
<%= f.fields_for :cards do |card| %>
<%= render 'card_fields', f: card %>
<% end %>
<%= link_to_add_association f, :cards, class: "add-cards" do %>
<span>Add Card</span>
<% end %>
</div>
<%= f.submit "Update" %>
<% end %>
and in my controller removed the #order.cards.build from the edit action.
Reason for the div, is the JS was inserting the fields for outside the actual form.

Form which creates a quantity of another model with form field

I have two models, Hotel and Room. I want to create a form that will allow me to add a new hotel and rooms, which indicates the name of the hotel and the quantity of rooms.
I know I should use "nested form", but it is hard for me to implement it properly.
Here is my code:
HotelsController
class HotelsController < ApplicationController
def index
#hotels = Hotel.all
end
def new
#hotel = Hotel.new
end
def create
#hotel = Hotel.new(hotel_params)
if #hotel.save
redirect_to #hotel
else
render 'new'
end
end
def show
#hotel = Hotel.find(params[:id])
end
def destroy
#hotel = Hotel.find(params[:id])
#hotel.destroy
redirect_to hotels_url, notice: 'Hotel was successfully destroyed.'
end
private
def hotel_params
params.require(:hotel).permit(:name, :rooms_count)
end
end
Hotel model
class Hotel < ApplicationRecord
has_many :rooms, dependent: :destroy
accepts_nested_attributes_for :rooms
end
Room model
class Room < ApplicationRecord
belongs_to :hotel, optional: true # avoiding rails 5.2 belongs_to error
end
form
<%= form_with scope: :hotel, url: hotels_path, local: true do |form| %>
<p>
<%= form.label :name %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.label :rooms_count %><br>
<%= form.number_field :rooms_count %>
</p>
<p>
<% form.fields_for :rooms do |f|%>
<p>
**THE CODE**
</p>
<% end %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
You forgot the "ERB echo sign" (=) on the fields_for helper.
Correct form:
<%= form.fields_for :rooms do |f|%>
I have found a solution to my question.
def create
#hotel = Hotel.new(hotel_params)
#hotel.rooms_count.times do
#hotel.rooms.build
end
if #hotel.save
redirect_to #hotel
else
render 'new'
end
end
It implement a #hotel.rooms.build as many times as #hotel.rooms_count number entered in Rooms Count field in form.

how should i use single model for multiple controller in rails apllication

<center><h1> welcome </h1></center>
<%= form_for :authors , url: auth_path do |f| %>[this is the controller auth and model author]
<p>
<%= f.label :title %><br>
<%= f.text_field :topic %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :content ,:cols => "30", :rows => "10" %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
the error is
ActionController::UrlGenerationError in Auth#new
[controller code check it is right or not]
i have tried for it but nothing works
can any one correct the code
class AuthController < ApplicationController
def index
#author = Author.all
end
def show
#author = Author.find(params[:id])
end
def new
end
def create
#author = Author.find(params[:id])
#auth = #author.comments.create(comment_params)
redirect_to #author
end
private
def author_params
params.require(:author).permit(:topic, :content)
end
end
In controller define method same name as this page name in that get #author = Author.find(params[:id]) and in view
<%= form_for #author, :as => :author, :url => auth_path(#author) do |f| %>
And to use single model for multiple controller
class User::AuthorsController < ApplicationController
def welcome
end
end
or
module User
class AuthorsController < ApplicationController
def welcome
end
end
end
You can also call your partials this way
render :template => "user/authors/welcome"
Then in routes.rb
namespace :user do
resources :authors
end

How to add tags to posts using checkbox?

I want to build a many-to-many association through tagging between posts and tags. Users can create posts with tags by checking the existed tags. But I don't know how to create a nested form and save the association.
My form
<%= form_for(#post) do |f| %>
<div class="field">
<%= f.label :text %><br />
<%= f.text_field :text %>
</div>
<div>
<%= hidden_field_tag "post[tag_ids][]", nil %>
<% Tag.all.each do |tag| %>
<%= check_box_tag "post[tag_ids][]", tag.id, #post.tag_ids.include?(tag.id) %>
<%= tag.name %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
posts controller here:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:text)
end
end
Model
class Post < ActiveRecord::Base
has_many :taggings
has_many :tags, :through => :taggings
end
class Tag < ActiveRecord::Base
has_many :taggings
has_many :posts, :through => :taggings
end
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :post
end
I don't think you actually need to have a nested form in this case. Rails automagically figures out the association, when given the attribute :tag_ids
This is what I did for a multiselect form_helper, which would need minor changes for a check_box helper
f.select :tag_ids, Tag.all.collect {|tag| [tag.name, tag.id]}, {}, :multiple => true

Update Cancan in rails

im doing an authorisation application where:
-have admin role, who can manage everything.
-have guest role, who can create posts and edit the posts which he has created.
im facing problem with the guest role. I have done associations where:
-posts belongs_to user(In post model am having user_id attribute also in migration i have referenced posts to users)
-user has_many posts.
when im tryin to create a new post, the user_id is nil. i dunno how to set user_id attribute in Post object.
class ProductsController < ApplicationController
before_filter :self_load, :only=>[:show,:edit,:update,:destroy]
before_filter :authenticate_user, :only=>[:edit,:update,:destroy]
def index
#products=Product.find(:all)
end
def new
#product=Product.new(:user_id=>current_user.id)
end
def create
#product=Product.new(params[:product])
if #product.save
redirect_to root_url, :notice=>'New Product has been added'
else
render :action=>'new'
end
end
def show
end
def edit
end
def update
if #product.update_attributes(params[:product])
redirect_to root_url, :notice=>'Product has been updated.'
else
render :action => 'edit'
end
end
def destroy
#product.destroy
redirect_to root_url
end
def self_load
#product = Product.find(params[:id])
end
def authenticate_user
if current_user
else
redirect_to root_url, :notice=>'You are not authorised to access'
end
end
end
view:
Add Product
<%= form_for(#product) do |f| %>
<% if #product.errors.any? %>
<ul>
<% #product.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<table>
<tr><td><%= f.label 'Title:' %></td>
<td><%= f.text_field :title %></td>
<tr><td><%= f.label 'Description:' %></td>
<td><%= f.text_area :description,:rows=>10 %></td></tr>
<tr><td><%= f.label 'Price:' %></td>
<td><%= f.text_field :price %></td></tr>
<tr><td><%= f.submit 'Save' %></td></tr>
</table>
<% end %>
<%= link_to 'Back', root_url %>
Model
class Product < ActiveRecord::Base
belongs_to :user
attr_accessible :title, :description, :price, :user_id
validates_presence_of :title, :description, :price
validates_uniqueness_of :title
validates_length_of :title, :in=>4..10
validates_length_of :description, :minimum=>10
validates_numericality_of :price
end
Plz help me with this.... if u need any further info u can ask...
if only signed in user can create products, try this
class ProductsController < ApplicationController
def create
#product = current_user.products.build params[:product]
if #product.save
# Stuff is product save succesfully
else
# Stuff is product does not saved
end
end
end

Resources