I have three models:
category.rb
class Category
include Mongoid::Document
# Relationships
has_many :posts, :autosave => true
has_many :boards, :autosave => true
accepts_nested_attributes_for :boards
accepts_nested_attributes_for :posts
#fields
field :name
#attr
attr_accessible :name
end
My model board.rb
class Board
include Mongoid::Document
# Relationships
has_many :posts, :dependent => :destroy , :autosave => true
accepts_nested_attributes_for :posts
belongs_to :category
#fields
field :name
field :description
#attr
attr_accessible :name, :posts_attributes, :description, :category_id
end
My post.rb
class Post
include Mongoid::Document
# Relationships
belongs_to :board
belongs_to :category
belongs_to :user
#fields
field :content
#attr
attr_accessible :content :board_id, :category_id
end
In my posts_controller
def create
#post = current_user.posts.new(params[:post])
#board = #post.board
#board.user = current_user
if #board.category_id?
#post.category_id = #board.category_id
end
respond_to do |format|
if #post.save
format.html { redirect_to root_url, notice: 'Post was successfully created.' }
format.json { render json: root_url, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
In my view new action:
<%= form_for(#post) do |f| %>
<%= f.text_area :content %>
<%= f.collection_select :board_id, Board.where(:user_id => current_user.id), :id, :name%>
<%= f.submit :id => "button_submit_pin_edit" %>
<% end %>
The boards in select field, may or may not have a parent category already assigned.
I want get the attributes from category (the name of the category for this event) in my post view without using a select field, or an input field.
with this code in posts.controller.rb
if #board.category_id?
#post.category_id = #board.category_id
end
I see in my console for Post.first e.j.:
<Post _id: 4f1d96241d41c8280800007c, _type: nil, created_at: 2012-01-23 17:17:24 UTC, user_id: BSON::ObjectId('4f0b19691d41c80d08002b20'), board_id: BSON::ObjectId('4f1455fa1d41c83988000510'), category_id: BSON::ObjectId('4f1c2d811d41c8548e000008'), content: "nuevo post">
If I write:
post = Post.first
and
post.board
I get the object board fine. This does works fine.
but If I write:
post.category
I get:
=> nil
I have try in view new post add hidden field:
hidden_field(:category, :name)
How can I get the params of object category?
Thanks
Don't set it using the ID fields. Instead of this in your PostsController:
if #board.category_id?
#post.category_id = #board.category_id
end
Try this line:
#post.category = #board.category
Which will set the #post.category belongs_to relationship to point to #board.category assuming it exists (is not nil). Mongoid will handle the setting of the category_id field for you. Read the mongoid documentation about relationships for a more detailed explanation.
Related
I have three models Book_Room, Invoice, and Bill. Invoice belongs to BookRoom, and has many bills. the error is unpermitted params error for :invoice is thrown when i try to create Book Room after ive clearly asked to accept nested params
class Invoice < ApplicationRecord
belongs_to :book_room
has_many :bills
accepts_nested_attributes_for :bills
end
And BookRoom is meant to have only one invoice, but I used has_many because the fields_for form doesn't render when I use has_one.
class BookRoom < ApplicationRecord
belongs_to :customer
has_and_belongs_to_many :rooms
has_many :invoices
accepts_nested_attributes_for :invoices
end
Here is my create action for invoice controller:
def create
#booking = BookRoom.find(params[:book_room_id])
#invoice = #booking.invoice.new(invoice_params)
if #invoice.save
redirect_to #invoice, notice: 'Invoice was successfully created.'
else
render :new
end
end
And here is my form, which is meant to create invoices and bills.
<%= f.fields_for :invoice do |i| %>
<%= i.fields_for :bill do |b| %>
<%= b.label :price %>
<%= b.number_field :price %>
<%= b.hidden_field :type, value: :deposit %>
<% end %>
<% end %>
And finally, my book_room controller:
def create
#book_room = #customer.book_rooms.new(book_room_params)
if #book_room.save
redirect_to #book_room, notice: 'Book room was successfully created.'
else
render :new
end
end
def book_room_params
params.require(:book_room).permit(:customer_id, :start_date, :end_date, :room_ids=>[], :invoices_attributes => [ :invoice_id, :bills_attributes => [:price, :type] ])
end
When I try to create a book room with bill records, it throws an error of unpermitted params invoice. If there is a way to get the form to render on has_one relationship, I will appreciate it.
Try switching to has_one :invoice association - fields_for can work with it, but you need to build association first with #book_room.build_invoice in BookRoomController#new controller action.
Then you can fix book_room_params - change invoices_attributes key to singular invoice_attributes.
I'm a noob to Rails and have been working on this for 3-4 days. I've created a many-to-many :through association, but when I submit a new object, I get this error:
#<ActiveModel::Errors:0x007fbced7cda88 #base=#<BlogPost id: nil, created_at: nil, updated_at: nil, title: "title 13", content: "pajfposjpfej 13", posted_by: "poster 13", comments: nil, blog_pic: nil>, #messages={:"categorizations.blog_post"=>["must exist"], :title=>[], :posted_by=>[], :content=>[], :blog_pic=>[]}, #details={"categorizations.blog_post"=>[{:error=>:blank}]}>
My form submission I'm submitting I'm selecting a category so it shouldn't be empty as the error indicates. Really appreciate any help with this. Demoralized for days now.
models:
class BlogPost < ApplicationRecord
has_many :categorizations
has_many :categories, :through => :categorizations
accepts_nested_attributes_for :categorizations
has_many :comments
mount_uploader :blog_pic, BlogPicUploader
end
class Categorization < ApplicationRecord
belongs_to :blog_post
belongs_to :category
end
class Category < ApplicationRecord
has_many :categorizations
has_many :blog_posts, :through => :categorizations
end
views/blog_posts/new.html.erb
<%= form_for #blog_post do |b| %>
<%= b.label :title %>
<%= b.text_field :title %><br>
<%= b.fields_for :categorizations do |cat| %>
<%= cat.label :category_name, "Category 1" %>
<%= cat.collection_select(:category_id, Category.all, :id, :category_name, include_blank: "Select Category") %><br>
<% end %>
<%= b.submit "Submit", class: "btn btn-primary" %>
<% end %>
controller:
class BlogPostsController < ApplicationController
def index
#blog_posts = BlogPost.order(id: :desc)
end
def new
#blog_post = BlogPost.new
#categorizations = #blog_post.categorizations.build
#categories = #blog_post.categories.build
end
...
def create
#blog_post = BlogPost.new(blog_post_params)
respond_to do |format|
if #blog_post.save
format.html { redirect_to #blog_post, notice: 'Your blog was submitted successfully' }
format.json { render :show, status: :created, location: #blog_post }
else
format.html { render :new }
format.json { render json: #blog_post.errors, status: :unprocessable_entity }
end
end
puts #blog_post.errors.inspect
end
private
def blog_post_params
params.require(:blog_post).permit(:title, :content, :posted_by, :comments, :blog_pic, {categorizations_attributes: [:category_id, :category_name]})
end
end
you need to declare nested attribute for categories as well.
like:
class BlogPost < ApplicationRecord
has_many :categorizations
has_many :categories, :through => :categorizations
accepts_nested_attributes_for :categorizations
accepts_nested_attributes_for :categories
has_many :comments
mount_uploader :blog_pic, BlogPicUploader
end
You can refer below link for description
https://hackhands.com/building-has_many-model-relationship-form-cocoon/
The answer here had nothing to do with the code - simply put - in Rails 5, they've made a change that now requires belongs_to association by default, where as in Rails 4, this was optional. See link below that explains:
http://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html
You have to change this line in config/initializers/new_framework_defaults from true to false:
Rails.application.config.active_record.belongs_to_required_by_default = false
I'm trying to create a view allowing me to create and edit values of my joining table directly. This model is called 'hires'. I need to be able to create multiple rows in my joining table for when a child hires up to 2 books. I'm having some trouble and I suspect it's down to my associations...
I have 3 models. Each Child can have 2 books:
class Child < ActiveRecord::Base
has_many :hires
has_many :books, through: :hires
end
class Hire < ActiveRecord::Base
belongs_to :book
belongs_to :child
accepts_nested_attributes_for :book
accepts_nested_attributes_for :child
end
class Book < ActiveRecord::Base
has_many :hires
has_many :children, through: :hires
belongs_to :genres
end
The controller looks like this:
class HiresController < ApplicationController
...
def new
#hire = Hire.new
2.times do
#hire.build_book
end
end
def create
#hire = Hire.new(hire_params)
respond_to do |format|
if #hire.save
format.html { redirect_to #hire, notice: 'Hire was successfully created.' }
format.json { render :show, status: :created, location: #hire }
else
format.html { render :new }
format.json { render json: #hire.errors, status: :unprocessable_entity }
end
end
end
...
private
# Use callbacks to share common setup or constraints between actions.
def set_hire
#hire = Hire.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def hire_params
params.require(:hire).permit(:child_id, book_attributes: [ :id, :book_id, :_destroy])
end
end
The view likes this:
<%= form_for(#hire) do |f| %>
<%= f.label :child_id %><br>
<%= f.select(:child_id, Child.all.collect {|a| [a.nickname, a.id]}) -%>
<%= f.fields_for :books do |books_form| %>
<%= books_form.label :book_id %><br>
<%= books_form.select(:book_id, Book.all.collect {|a| [a.Title, a.id]}) %>
<%# books_form.text_field :book_id #%>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
The problem is, the hash is not submitting books_attributes as you'd expect, it's just submitting 'books':
Processing by HiresController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xx", "hire"=>{"child_id"=>"1", "books"=>{"book_id"=>"1"}}, "commit"=>"Create Hire"}
Unpermitted parameter: books
I suspect this is because my associations for the Hire model are:
belongs_to :book
accepts_nested_attributes_for :book
which means I can't build the attributes correctly but I'm not sure how to solve this. Any help would be great, am I solving this problem badly?
Try changing books_attributes to book_attributes in strong paramters for hire_param.
def hire_params
params.require(:hire).permit(:child_id, book_attributes: [ :id, :book_id, :_destroy])
end
Need advise, how to fix creating multiple nested records in rails.
My code:
Models
class Category < ActiveRecord::Base
has_many :fcatalogs
has_many :features, :through => :fcatalogs
accepts_nested_attributes_for :fcatalogs
end
class Feature < ActiveRecord::Base
has_many :fcatalogs
has_many :categories, :through => :fcatalogs
accepts_nested_attributes_for :fcatalogs
end
class Fcatalog < ActiveRecord::Base
self.table_name = 'categories_features'
belongs_to :category
belongs_to :feature
end
In controller
def new
#category = Category.new
#category.fcatalogs.build
end
def create
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to [:admin, #category], notice: category_params } #'Category was successfully created.'
format.json { render action: 'show', status: :created, location: #category }
else
format.html { render action: 'new' }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def category_params
params.require(:category).permit(:parent_id, :name, :description, :url, :image, :position, :visible, :meta_title, :meta_keywords, :meta_description,
:fcatalogs_attributes: [:feature_id])
end
In view
<%= f.fields_for :fcatalogs do |builder| %>
<%= builder.label :feature_id, 'Feature' %>
<%= builder.collection_select(:feature_id, Feature.all, :id, :name, {}, {:multiple => true, :size => 5}) %>
<% end %>
If i remove :multiple => true, :size =>5 condition, single nested record successfully creates,
but with :multiple it fails with error: Unpermited param feature_id
If someone else stumbles upon this:
I think you should change your params to :feature_ids, since you're looking for multiple records. Change it in the controller AND in the view!
Hi I'm currently working on my first rails project, a site for users to make albums and upload pics. I have the registration, logging in, and friending installed into my app. I'm trying to make it so that in the album creation form, you can see a list of your friends and select who you want to share access to the album with (meaning whoever you select would also be part of #album.users. I'm planning on using a checkbox (I can't think of any better way) to make this selection. However, I am not sure how to link the friendship model with the album/new form. This is how my form looks like:
album/new.html.erb
<%= form_for ([#user, #album]), :html => { :id => "uploadform", :multipart => true } do |f| %>
<div class="formholder">
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.check_box :friends %>
<%= f.label :description %>
<%= f.text_area :description %>
<br>
<%=f.submit %>
</div>
<% end %>
an error occurs on line #6 (
<%= f.check_box :friends %>
the error:
undefined method 'friends' for #<Album:0x007fa3a4a8abc0>
I can understand why, but I don't know how to fix it. I have the typical friendship join model to add friends, and I want to be able to see a list of all the friends and select them. I think a following step would be to add something like #album.users << #user.friendships.find_by_name(params[:friends]) in the create action in the albums controller, but I don't know how I would loop through the form that only returns one param for friends?
Here are my files:
Albums controller create action:
def create
#user = User.find(params[:user_id])
#album = #user.albums.build(params[:album])
# not so sure about the following line.
#album.users << #user.friendships.find_by_name(params[:friends])
respond_to do |format|
if #user.save
format.html { redirect_to user_album_path(#user, #album), notice: 'Album was successfully created.' }
format.json { render json: #album, status: :created, location: #album}
else
format.html { render action: "new" }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
album model
class Album < ActiveRecord::Base
attr_accessible :name, :description
validates_presence_of :name
has_many :album_users
has_many :users, :through => :album_user
has_many :photos
end
user model
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :name, :password, :password_confirmation
validates_presence_of :password, :on => :create
validates_format_of :name, :with => /[A-Za-z]+/, :on => :create
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates_length_of :password, :minimum => 5, :on => :create
has_many :album_users
has_many :albums, :through => :album_users
accepts_nested_attributes_for :albums
has_many :friendships
has_many :friends, :through => :friendships
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
album_user model (join table to make many-to-many relationship between album, which has many users, and users, which has many albums)
class AlbumUser < ActiveRecord::Base
belongs_to :album
belongs_to :user
end
friendship model
class Friendship < ActiveRecord::Base
attr_accessible :friend_id
belongs_to :user
belongs_to :friend, :class_name => "User"
end
let me know if you need any more info!! Thanks in advance!!!
You should add users_ids (yes, two "s") to the list of accessible attributes of Album, and then use a "select multiple" on the :users_ids field.
<%= f.collection_select(:users_ids, User.all, :id, :name, :multiple => true) %>