I have model of course, every course has many units, every unit has many videos and has one quiz and finally every quiz has many questions.
When I try to add new course or edit one, this is the error I get:
undefined method `has_one' for #
Did you mean? has_many
This are my models:
Course.rb
class Course < ApplicationRecord
validates_presence_of :title
validates_presence_of :author
has_many :units, dependent: :destroy, autosave: true
accepts_nested_attributes_for :units, allow_destroy: true
acts_as_paranoid
end
Unit.rb
class Unit < ApplicationRecord
validates_presence_of :name
validates_presence_of :course_id
belongs_to :course
has_many :videos, dependent: :destroy, autosave: true
has_one :quiz, dependent: :destroy, autosave: true
accepts_nested_attributes_for :videos, allow_destroy: true
accepts_nested_attributes_for :quiz, allow_destroy: true
acts_as_paranoid
end
Video.rb
class Video < ApplicationRecord
validates :data ,presence: true
validates_presence_of :unit
validates_presence_of :unit_id
validates_presence_of :name
belongs_to :unit
acts_as_paranoid
end
Quiz.rb
class Quiz < ApplicationRecord
validates_presence_of :name
validates_presence_of :unit
validates_presence_of :unit_id
belongs_to :unit
has_many :questions, :dependent => :destroy, :autosave => true
accepts_nested_attributes_for :questions, allow_destroy: true
acts_as_paranoid
end
Question.rb
class Question < ApplicationRecord
validates :question ,presence: true
validates :answer1 ,presence: true
validates :answer2 ,presence: true
validates :answer3 ,presence: true
validates :answer4 ,presence: true
validates :correct ,presence: true
validates_presence_of :segment
belongs_to :quiz
acts_as_paranoid
end
This is the courses.rb in active admin:
ActiveAdmin.register Course do
permit_params :id, :title, :author, :course_details, :course_expectations, :course_time, :course_topics, :course_additional_resources,
units_attributes: [:id, :name, :_destroy, :_create, :_update,
videos_attributes: [:id, :name, :data],
quiz_attributes: [:id, :name,
questions_attributes: [:id, :question, :answer1, :answer2, :answer3, :answer4, :correct, :_destroy, :_create, :_update]]]
config.sort_order = 'id_asc'
active_admin_paranoia
# /admin/course/:id/units
member_action :units do
#units = resource.units
# This will render app/views/admin/courses/units.html.erb
end
index do
column :id
column :title
column :author
actions
end
show do
panel "About this course" do
div do
label "Course Topics:"
span course.course_topics
end
div do
label "Course Expectations:"
span course.course_expectations
end
div do
label "Time:"
span course.course_time
end
div do
label "Additional Resources:"
span course.course_additional_resources
end
end
panel "Course Overview" do
table_for course.units do
column "Unit name", :name
column(:videos) {|unit|
table_for unit.videos do
column :id
column :name
column :data
end
}
column(:quiz) { |unit|
if unit.quiz
table_for unit.quiz do
column :id
column :name
column :question
column :answer1
column :answer2
column :answer3
column :answer4
column :correct
end
else
'No Quiz'
end
}
end
end
active_admin_comments
end
sidebar "Course Units", only: :show do
# sidebar "Course Details", only: :show do
# attributes_table_for course do
# row :title
# row :author
# end
table_for Unit.joins(:course).where(:course_id => course.id) do |t|
t.column("Title") { |unit| unit.name }
end
end
form do |f|
tabs do
tab 'Basic Info' do
f.inputs "Course details" do
f.input :title
f.input :author
f.input :course_topics
f.input :course_expectations
f.input :course_time
f.input :course_additional_resources
end
end
tab 'Content' do
f.inputs "Units" do
f.has_many :units, heading: false, allow_destroy: true do |unit|
unit.input :name
unit.has_many :videos, heading: false, allow_destroy: true do |video|
video.input :name
video.input :data, label: 'Url', :as => :string, input_html: { class: 'video-tab' }
end
unit.has_one :quiz, heading: false, allow_destroy: true do |quiz|
quiz.has_many :questions, heading: false, allow_destroy: true do |q|
q.input :question, input_html: { class: 'quiz-tab' }
q.input :answer1, input_html: { class: 'quiz-tab' }
q.input :answer2, input_html: { class: 'quiz-tab' }
q.input :answer3, input_html: { class: 'quiz-tab' }
q.input :answer4, input_html: { class: 'quiz-tab' }
q.input :correct, input_html: { class: 'quiz-tab' }, as: :select, collection: [1,2,3,4]
end
end
end
end
end
end
f.actions
end
end
Related
I want the user to search through existing items from the items table in the orders form, it works for clients but not for items, it gives an error: Association :item not found
Models
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :client
has_many :order_items
has_many :items, :through => :order_items
end
class Item < ActiveRecord::Base
has_many :order_items
has_many :orders, :through => :order_items
end
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
end
Migration
class CreateOrderItems < ActiveRecord::Migration
def change
create_table :order_items do |t|
t.integer :item_id
t.integer :order_id
t.timestamps
end
add_index :order_items, [:item_id, :order_id]
end
end
View
<%= simple_form_for(#order) do |f| %>
<%= f.error_notification %>
<%= f.association :client, collection: Client.all, label_method: :name, value_method: :id, prompt: "Choose a Client", input_html: { id: 'client-select2' } %>
<%= f.association :item, collection: Item.all, label_method: :name, value_method: :id, prompt: "Choose an item", input_html: { id: 'client-select2' } %>
<%= f.input :memo, label: 'Comments' %>
<%= f.submit %>
<% end %>
Controller
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
end
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, items_attributes: [:id, :name, :price, :quantity, :status, :_destroy])
end
Answer
In the form use instead:
using rails-select2 gem
<%= f.association :items, collection: Item.all, label_method: :name, value_method: :id, prompt: "Choose an item", input_html: { id: 'item-select2' } %>
or without select2
<%= f.select :item_ids, Item.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
Thanks to JKen13579
The reason that you're receiving the error for item but not for client is because there is one client associated to an order, but more than one item associated to an order. It's saying :item not found because you should be using :items (note the plural).
To allow multi-select for your order's items, replace your f.association item line with:
<%= f.select :item_ids, Item.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
And then in your controller, be sure to permit item_ids. In addition, you don't need item_attributes, because you're not using accepted_nested_attributes_for :items.
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, item_ids: [])
end
See this SO answer for more information about has_many :through multi-select.
I'm creating a site that has events. Each event acts as a gallery and has_many images. Each image belongs_to and event.
I followed the RailsCast #253 CarrierWave gem. When I try to add a new image, it says
undefined method `event_id' for # Image:0x7302438
<%= form_for #image, :html => {:multipart => true} do |f| %>
<%= f.error_messages %>
<%= f.hidden_field :event_id %>
<%= f.label :title %><br />
<%= f.text_field :title %>
Here is my image.rb
class Image < ActiveRecord::Base
attr_accessible :event_id, :title, :image
validates :title, :image, :presence => :true, :uniqueness => :true
belongs_to :event
mount_uploader :image, ImageUploader
end
and the event.rb
class Event < ActiveRecord::Base
attr_accessible :title, :date, :about
validates :title, :about, :date, :presence => :true
validates :title, :uniqueness => :true
has_many :images
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
end
Running this in a migration worked. Column wasn't added.
def up
change_table :images do |t|
t.references :event
end
end
I have models product and product images. Product_images is a paperclip model. Product has many product_images. I am making an Active Admin form which uploads multiple images and shows these images to the Products view page.
However, when I save the product. The product table is updated, but not the product_image table. Image attaching normally, but I can't update fields of already uploaded image.
class Product < ActiveRecord::Base
attr_accessible :name, :product_images_attributes
has_many :product_images, :dependent => :destroy
accepts_nested_attributes_for :product_images, :reject_if => lambda { |t| t['product_image'].nil? }, :allow_destroy => true
end
class ProductImage < ActiveRecord::Base
attr_accessible :name, :style
attr_accessible :image
belongs_to :product
has_attached_file :image, :styles => { :small => "150x150>", :large => "320x240>" }
validates_attachment_presence :image
end
ActiveAdmin.register Product do
form :html => { :multipart => true } do |f|
f.inputs "Admin Details" do
f.input :name
end
f.inputs "Product images" do
f.has_many :product_images do |p|
p.input :style, :as => :select, :collection => Image::STYLES, :include_blank => false
p.input :image, :as => :file, :label => "Image",:hint => p.object.image.nil? ? p.template.content_tag(:span, "No Image Yet") : p.template.image_tag(p.object.image.url(:small))
p.input :_destroy, :as=>:boolean, :required => false, :label => 'Remove image'
end
end
f.buttons
end
UPDATE
In the products model I do:
after_update :check
def check
if ProductImage.find_by_product_id(self.id).changed?
raise "image"
else
raise "fail"
end
end
and it's alway raise "fail"
I got the same error using rails 4.1. Just solved this.
I noticed that warnings in my output:
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
So I just passed them to permit_params:
permit_params assets_attributes: [:image, :image_file_name, :image_content_type, :image_file_size, :image_updated_at, :_destroy, :id]
to AA's resource page. And it worked.
I hope it will help.
If not - here is my listings.
ActiveAdmin.register Product do
permit_params :name, :description, :price, :brand_id, :category_id, assets_attributes: [:image, :image_file_name, :image_content_type, :image_file_size, :image_updated_at, :_destroy, :id]
form multipart: true do |f|
f.inputs "Детали" do
f.input :category_id, as: :select, collection: Category.all, include_blank: false
f.input :brand_id, as: :select, collection: Brand.all, include_blank: false
f.input :name
f.input :description
f.input :price
end
f.inputs 'Фотографии' do
f.has_many :assets, allow_destroy: true, heading: 'Фото', new_record: false do |fasset|
fasset.input :image, as: :file, hint: fasset.template.image_tag(fasset.object.image.url(:thumb))
end
end
f.actions
end
end
class Product < ActiveRecord::Base
belongs_to :category
belongs_to :brand
has_many :assets, dependent: :destroy, autosave: true
accepts_nested_attributes_for :assets, allow_destroy: true,
:reject_if => lambda { |attributes| attributes[:image].blank? }
validate :name, presence: true
validate :description, presence: true
validate :price, presence: true
end
class Asset < ActiveRecord::Base
belongs_to :product
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
validates_with AttachmentPresenceValidator, :attributes => :image
end
You can configure ActiveRecord to cascade-save changes to items in a collection for a model by adding the :autosave => true option when declaring the association.
Try:
has_many :product_images, :dependent => :destroy, :autosave => true
Also, you can save the table data on association in the after_save callback like this:
class Product < ActiveRecord::Base
attr_accessible :name, :product_images_attributes
has_many :product_images, :dependent => :destroy
accepts_nested_attributes_for :product_images, :reject_if => lambda { |t| t['product_image'].nil? }, :allow_destroy => true
after_save :do_product_image_update
private
def do_product_image_update
self.product_images.save
end
end
It's the third day I'm crushing on Active Admin.
I have #survey that has_many :questions and each question has_many :answers - they are actually variants users can choose from.
But still I cant put it to work, it just doesn't create anything deeper then 1 level:
even the form works properly, but nothing is created.
I have the following clases Course->Sections->Lessons.
I did the following:
form do |f|
f.inputs "Details" do
f.input :instructor, :as => :select
f.input :title
f.input :name
f.input :price
f.input :discount
f.input :slug
f.inputs "Sections" do
f.has_many :sections, :header=>"" do |section|
section.input :name
section.input :position
if section.object.id
section.input :_destroy, :as=>:boolean, :required => false, :label=>'Remove'
end
section.has_many :lessons, :header=>"Lessons" do |lesson|
lesson.input :title
lesson.input :position
lesson.input :duration
lesson.input :_destroy, :as=>:boolean, :required => false, :label=>'Remove'
end
end
end
end
f.buttons
end
My models are as follow:
class Course < ActiveRecord::Base
has_many :sections, :dependent => :delete_all
accepts_nested_attributes_for :sections, :allow_destroy => true
attr_accessible :sections_attributes
....
class Section < ActiveRecord::Base
belongs_to :course
has_many :lessons, :dependent => :delete_all
attr_accessible :course_id, :name, :position
accepts_nested_attributes_for :lessons, :allow_destroy => true
attr_accessible :lessons_attributes
....
class Lesson < ActiveRecord::Base
belongs_to :section
attr_accessible :duration, :position, :section_id, :title
....
And it works great! I don't know what happens if I go more levels deeper.
I have the following Models:
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
attr_accessible :name, :post_id
end
class Post < ActiveRecord::Base
belongs_to :topic, :touch => true
has_many :comments, :dependent => destroy
accepts_nested_attributes_for :topic, :comments
attr_accessible :name, :title, :content, :topic, :topic_attributes
end
class Comment < ActiveRecord::Base
belongs_to :Post
end
Is this simple form valid? Can I access 2 nested Models at the same time?
simple_form_for #post do |f|
f.simple_fields_for :topic do |topic_form|
topic_form.input :name
end
f.simple_fields_for :comment do |comment_form|
comment_form.input :text
end
end
Thanks
Try this
simple_form_for #post do |f|
f.simple_fields_for #post.topic do |topic_form|
topic_form.input :name
end
f.simple_fields_for #post.comments do |comment_form|
comment_form.input :text
end
end