Hi I have a polymorphic association with for a Document model for storing document uploads. I'm trying to submit the document attributes as a nested attribute via the associated model.
However, when I load the form, the nested field does not show. What am I missing?
Schema:
create_table "documents", force: :cascade do |t|
t.json "links"
t.integer "linkable_id"
t.string "linkable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "documents", ["linkable_type", "linkable_id"], name: "index_documents_on_linkable_type_and_linkable_id", using: :btree
Models:
class Document < ActiveRecord::Base
belongs_to :linkable, polymorphic: true
belongs_to :user
belongs_to :company
mount_uploaders :links, DocUploader
end
class CustomerPlan < ActiveRecord::Base
has_many :documents, as: :linkable
accepts_nested_attributes_for :documents
end
Controller:
class CustomerPlanController < ApplicationController
def new
#customer_plan = current_company.customer_plans.build
end
def create
#customer_plan = current_company.customer_plans.build(customer_plan_params)
if #customer_plan.save
redirect_to #customer_plan, notice: 'Customer plan was successfully created.'
else
render :new
end
end
private
def cusomter_plan_params
params.require(:cusomter_plan_params).permit(:date, :name, :plan_type,
documents_attributes: [:id, links: []])
end
end
Form:
<%= simple_nested_form_for #stock_plan, :html => { :multipart => true } do |f| %>
<%= f.error_notification %>
<%= f.input :date %>
<%= f.input :name %>
<%= f.input :plan_type %>
<%= f.simple_fields_for :documents do |d| %>
<p><b>Upload here:</b></p>
<%= d.file_field :links, multiple: true %>
<br>
<% end %>
<%= f.button :submit%>
<% end %>
Related
I'm trying to save an organization to a contact model via a form using a collection_select helper but it's not saving the data to a model. I can't seem to understand why.
I am using Rails 5.1.4
Here are my contact.rb model:
class Contact < ApplicationRecord
belongs_to :organization
has_many :deals
end
Here is my organization.rb model:
class Organization < ApplicationRecord
has_many :deals, through: :contacts
has_many :contacts, dependent: :destroy
end
Here is my schema.rb:
create_table "contacts", force: :cascade do |t|
t.string "contact_name"
t.integer "organization_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["organization_id"], name:
"index_contacts_on_organization_id"
end
create_table "organizations", force: :cascade do |t|
t.string "org_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Here is my contacts_controller.rb:
def new
#contact = Contact.new
end
def edit
#contact = Contact.find(params[:id])
end
def create
#contact = Contact.new(contact_params)
if #contact.save
redirect_to #contact
else
render 'new'
end
end
private
def contact_params
params.require(:contact).permit(:contact_name, :organization_id,
organizations_attributes: [:org_name,
:id])
end
Here is my new.html.erb file:
<h1>New Contact</h1>
<%= form_with scope: :contact, url: contacts_path, local: true do |form| %>
<p>
<%= form.label :contact_name %><br>
<%= form.text_field :contact_name %>
</p>
<p>
<%= form.label :organization %><br>
<%= form.collection_select(:organization_id, Organization.all, :id, :org_name) %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<hr>
Edit: I added params for my controller and schema.
In organization.rb model:
class Organization < ApplicationRecord
has_many :deals, through: :contacts
has_many :contacts, dependent: :destroy
def org_name
"#{name}"
end
end
in your new.html.erb file:
<%= form.fields_for :organizations do |o| %>
<%= o.collection_select(:organization_id, Organization.all,
:id, :org_name,
{:prompt => 'Please select the organization'}) %>
I have an issue adding Categories to article in my simple form.
The categories are showing up in the simple_form_for but the category_id is not attributed to the article when creating it ! (params ?)
Tx for your help !
I have created two models
class Category < ApplicationRecord
has_many :articles
end
class Article < ApplicationRecord
belongs_to :category
has_attachments :photos, maximum: 2
end
and a foreign key between them
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "card_summary"
t.text "summary"
t.integer "category_id"
t.index ["category_id"], name: "index_articles_on_category_id", using: :btree
end
The Articles controller to create an article
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to article_path(#article)
else
render :new
end
end
private
def article_params
params.require(:article).permit(:title, :card_summary, :summary, :body, photos: [])
end
and the simple_form_for where I used f.association (which shows correctly the different categories)
<%= simple_form_for #article do |f| %>
<%= f.input :title %>
<%= f.input :card_summary %>
<%= f.input :summary %>
<%= f.input :photos, as: :attachinary %>
<%= f.input :body %>
<%= f.association :category %>
<%= f.submit "Soumettre un article", class: "btn btn-primary" %>
<% end %>
I think my db is ok because I can attribute a category to an article with the console but I m stuck in this form. Any help would be much appreciated. Thx Edouard
EDIT
Here is my migration. Anything wrong?
class AddCategoryReferenceToArticles < ActiveRecord::Migration[5.0]
def change
add_reference :articles, :category, foreign_key: true, index: true
end
end
Adding category_id in article_params should solve the issue
def article_params
params.require(:article).permit(:title, :card_summary, :summary, :category_id, photos: [])
end
Could you please help with understanding why categories does not working in a right way? So I read quite a lot manuals about, and did not find how to resolve it
I created migration for category
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.text :description
t.integer :count
t.timestamps null: false
end
end
end
And added for posts new field - category
Then created model for category
class Category < ActiveRecord::Base
has_many :posts
end
Edit post model
class Post < ActiveRecord::Base
acts_as_ordered_taggable
belongs_to :category
validates :title, presence: true
validates :category, presence: true
..
end
Created template
<%= form_for #post do |f| %>
<p>
<%= f.label :title %> <br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :category %>
<%= f.select :category, Category.all.collect {|c| [c.name, c.name]} %>
</p>
<% end %>
Edited a bit post controller
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :thumbnail, :body, :description, :tag_list, :#post.category))
redirect_to #post
else
render 'edit'
end
end
change this line in your controller:
if #post.update(params[:post].permit(:title, :thumbnail, :body, :description, :tag_list, :category_id))
I changed
:#post.category
to
:category_id
This passes a symbol to the permit method to allow the request parameter for the category
I have set up a HABTM relationship between two table creating a many to many relationship between items and categories. I want to add an item connected with one or more categories via the add item form. when I submit the form I am getting the error "Can't mass-assign protected attributes: categories".
Here are my models:
class Item < ActiveRecord::Base
attr_accessible :description, :image, :name
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
belongs_to :user
has_and_belongs_to_many :categories
validates :name, presence: true, length: {maximum: 50}
accepts_nested_attributes_for :categories
end
class Category < ActiveRecord::Base
attr_accessible :description, :name
has_and_belongs_to_many :items
validates :name, presence: true, length: {maximum: 50}
end
And my migrations:
class CreateItems < ActiveRecord::Migration
def change
create_table :items do |t|
t.string :name
t.text :description
t.has_attached_file :image
t.timestamps
end
end
end
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.string :description
t.timestamps
end
end
end
class CreateCategoriesItems < ActiveRecord::Migration
def up
create_table :categories_items, :id => false do |t|
t.integer :category_id
t.integer :item_id
end
end
def down
drop_table :categories_items
end
end
And my form looks like this:
<%= form_for(#item, :html => { :multipart => true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_field :description %>
<%= f.file_field :image %>
<%= f.collection_select(:categories, #categories,:id,:name)%>
<%= f.submit "Add Item", :class => "btn btn-large btn-primary" %>
<% end %>
and here's my Items Controller:
class ItemsController < ApplicationController
def new
#item = Item.new
#categories = Category.all
end
def create
#item = Item.new(params[:item])
if #item.save
#sign_in #user
flash[:success] = "You've created an item!"
redirect_to root_path
else
render 'new'
end
end
def show
end
def index
#items = Item.paginate(page: params[:page], per_page: 3)
end
end
Thanks for all of your help :)
-Rebekah
Mass Assignment usually means passing attributes into the call that creates an object as part of an attributes hash.
Try this:
#item = Item.new(name: 'item1', description: 'description1')
#item.save
#category = Category.find_by_name('category1')
#item.categories << #category
Also see:
http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html
I hope this helps.
IAmNaN posted the comment above that was the missing link in my code working properly. I have since written a blog post that details the process of getting the HABTM set-up. Thanks IAmNaN!
Good day.
Has somebody working solution for deleting asset in nested form in Carrierwave?
MODEL
has_many :article_images, :dependent => :destroy
accepts_nested_attributes_for :article_images
mount_uploader :image, ImageUploader
belongs_to :article, :polymorphic => true
schema.rb
create_table "article_images", :force => true do |t|
t.string "image"
t.string "article_id"
end
create_table "articles", :force => true do |t|
t.string "title"
end
CONTROLLER
def edit
#article = Article.find(params[:id])
#article.article_images.build
end
VIEW
_form.html.erb
<%= f.fields_for :article_images do |article_image| %>
<% if article_image.object.new_record? %>
<%= article_image.file_field :image %>
<% else %>
<%= image_tag(article_image.object.image.url(:thumb)) %>
<%= article_image.check_box :remove_image %> #DON'T WORK
<% end %>
<% end %>
I think it's better if you do this:
class ArticleImage < ActiveRecord::Base
# ...
attr_accessible :remove_image
after_save :clean_remove_image
def changed?
!!(super || remove_image)
end
def clean_remove_image
self.remove_image = nil
end
end
It worked for me.
What happens if you add this to your accepts_nested_attributes_for in your model:
accepts_nested_attributes_for :article_images, :allow_destroy => true
and change this in your view code:
<%= article_image.check_box :remove_image %> #DON'T WORK
To this:
<%= article_image.check_box :_destroy %> #MIGHT WORK?