has_one relation in form in active admin - ruby-on-rails

I have two models/tabels: room and room_location, that have a one on one relation:
class Room < ApplicationRecord
has_one :room_location
end
class RoomLocation < ApplicationRecord
belongs_to :room
end
And this is what i want to do in my form in rooms.rb:
ActiveAdmin.register Room do
menu parent: 'Rooms'
permit_params :name, :description, room_location_attributes: [:address, :city]
form do |f|
f.inputs 'Roomsdata' do
f.input :name, as: :string
f.input :description
f.has_one :room_location do |t|
t.inputs do
t.address
t.city
end
end
f.actions
end
end
end
The has_one doesnt work and if i do has_many, it says relation "room_locations" does not exist

You should write in the params room_location_id instead of attributes
ActiveAdmin.register Room do
menu parent: 'Rooms'
permit_params :name, :description, room_location_id
form do |f|
address_id = ''
cs = params[:id].present? ? Case.find(params[:id]) : nil
unless cs.nil?
address_id = cs.address.id unless cs.address.nil?
end
f.inputs 'Roomsdata' do
f.input :name, as: :string
f.input :description
f.input :room_location_id , :as => :select, :collection => room_location.order(address: :desc).to_a.uniq(&:address).collect {|room_location| [room_location.address, room_location.id] }, selected: room_location_id
f.input :room_location_id , :as => :select, :collection => room_location.order(city: :desc).to_a.uniq(&:city).collect {|room_location| [room_location.address, room_location.id] }, selected: room_location_id
f.actions
end
end
end

Related

Rails 5.2 ActiveAdmin deep nested objects

I have this scheme: Course->Segments->Questions.
Course has many segments and segments has many questions.
I added segment_type attribute to segment model so I can show/hide question model depends on the type (video or quiz).
I managed to write the form in courses.rb and I got access to questions through course.
I'm having a problem with showing question attributes in show page even when I searched 3-4 hours on google for answer. Here is a screenshot of the show page
I wrote accept_nested_attribute in all the models so this is not the problem. I can edit, create and delete courses, segments and questions, it's just I can't see in the show the data relevant to questions.
EDIT: I know that the relations works fine in rails console and I have data in questions (it suppose to display the last segment's questions)
these are my models:
class Course < ApplicationRecord
validates :title ,presence: true
validates :author ,presence: true
has_many :segments, inverse_of: :course, :dependent => :destroy, :autosave => true
accepts_nested_attributes_for :segments, :allow_destroy => true
end
class Segment < ApplicationRecord
validates :course_id ,presence: true
validates :data ,presence: true, if: :segment_is_video?
validates :segment_type ,presence: true
validates_presence_of :course
belongs_to :course
has_many :questions, inverse_of: :segments, :dependent => :destroy, :autosave => true
accepts_nested_attributes_for :questions, :allow_destroy => true
def self.segment_type
{"Video": "Video", "Quiz": "Quiz"}
end
def segment_is_video?
segment_type == 'Video'
end
end
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 :segment
end
this is courses.rb:
ActiveAdmin.register Course do
permit_params :id, :title, :autor,
segments_attributes: [:id, :unit_id, :unit_title, :name, :segment_type, :data, :_destroy, :_create, :_update, questions_attributes: [:id, :question, :answer1, :answer2, :answer3, :answer4, :correct, :_destroy, :_create, :_update]]
config.sort_order = 'id_asc'
member_action :segments do
#segments = resource.segments
end
index do
column :id
column :title
column :author
actions
end
show do
panel "Course Segments" do
h3 "Videos"
table_for resource.segments.where('segment_type = "Video"') do
column :id
column :name
column :data
end
# Here it's only displaying id and name values, but the others no.
h3 "Quizes"
table_for resource.segments.where('segment_type = "Quiz"') do
column :id
column :name
column :question
column :answer1
column :answer2
column :answer3
column :answer4
column :correct
end
end
active_admin_comments
end
sidebar "Course Details", only: :show do
attributes_table_for course do
row :title
row :author
end
end
form do |f|
tabs do
tab 'Basic Info' do
f.inputs "Course details" do
f.input :title
f.input :author
end
end
tab 'Content' do
f.inputs "Segments" do
f.has_many :segments, heading: false, allow_destroy: true do |s|
s.input :unit_id
s.input :unit_title
s.input :name
s.input :segment_type, as: :select, collection: Segment.segment_type, input_html: { class: 'select-type' }
s.input :data, label: 'Url', :as => :string, input_html: { class: 'video-tab' }
s.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
f.actions
end
end

Pass current_admin_user.id into permit_params

In my application I have 2 models: AdminUser, which has_many :announcements, and Announcement, which belongs_to :admin_user. The Announcement table has admin_user_id column in a database.
In app/admin/announcement.rb I have:
ActiveAdmin.register Announcement do
permit_params :title, :body, :admin_user_id
controller do
def new
#announcement = Announcement.new
#announcement.admin_user_id = current_admin_user.id
end
end
form do |f|
f.inputs do
f.input :title
f.input :body, as: :ckeditor
end
f.actions
end
end
Why my controller doesn't work? When I create an announcement through activeadmin, the column admin_user_id is empty. How can I solve this issue?
Just added to a form: f.input :admin_user_id, as: :hidden, and now everything is working.

Activeadmin, duplicating has_many records

When I use ActiveAdmin to edit one Agency, I can select a City and associates it to the Agency. The city is linked to the Agency, but the city is all the times duplicated in the database.
My models:
# agency.rb
class Agency < ActiveRecord::Base
has_many :agency_cities
has_many :cities, through: :agency_cities
accepts_nested_attributes_for :cities, allow_destroy: true
end
# city.rb
class City < ActiveRecord::Base
has_many :agency_cities
has_many :agencies, through: :agency_cities
end
# AgencyCity.rb
class AgencyCity < ActiveRecord::Base
belongs_to :agency
belongs_to :city
end
I read the doc of Activeadmin and added the [:id] permit_parameter, but I still have the problem, I'm very confused.
# admin/agency.rb
ActiveAdmin.register Agency do
permit_params :name, :picture,
cities_attributes: [:id, :name, :description, :_destroy]
form do |f|
f.inputs "Agencies" do
f.input :picture, as: :file
f.input :creation_date, label: 'Creation Date'
f.input :name, label: 'Name'
end
end
f.inputs do
f.has_many :cities do |k|
k.input :name, label: 'City',
as: :select,
collection: City.all.map{ |u| "#{u.name}"}
k.input :_destroy, as: :boolean
end
end
f.actions
end
You are trying to associate the existing cities with an agency, so, you should do it this way:
ActiveAdmin.register Agency do
permit_params city_ids: [] # You need to whitelist the city_ids
form do |f|
f.inputs "Agencies" do
f.input :picture, as: :file
f.input :creation_date, label: 'Creation Date'
f.input :name, label: 'Name'
f.input :cities, as: :check_boxes, checked: City.pluck(&:id) # this will allow you to check the city names that you want to associate with the agency
end
end
end
This will allow you to associate the selected cities to the corresponding agency without creating (duplicating) new cities in the database. I think this is what you are looking for :-)
You can check in the generated html that the option values in the city select input are the name of the city (not the id).
Try this way: collection: City.all.map{ |u| [u.name, u.id]}
Some reference: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html

ActiveAdmin form: multiple nested forms

I have a structure User-> Profile-> Image and want to use one form for editing and recording in ActiveAdmin.
I use accepts_nested_attributes_forin models:
class User < ActiveRecord::Base
has_one :profile, dependent: :destroy;
accepts_nested_attributes_for :profile, allow_destroy: true
end
class Profile < ActiveRecord::Base
belongs_to :image, dependent: :destroy;
accepts_nested_attributes_for :image,:reject_if => proc { |attributes| !attributes['img'].present? }, :allow_destroy => true
end
class Image < ActiveRecord::Base
has_attached_file :img
validates_attachment_content_type :img, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
end
And such permit_params in ActiveAdmin.register User:
permit_params do
permitted=[:id,:login, :email, :admin, :password, :password_confirmation, :ip_address];
permitted.append(profile_attributes:[:name,:second_name,:middle_name,:img,:mobile_phone,:country, :city,:region, image_attributes:[:img]]);
permitted
end
Finally, the code itself forms
form do |f|
f.semantic_errors *f.object.errors.keys
f.inputs "User Details" do
f.input :login
f.input :email
f.input :password
f.input :password_confirmation
end
f.inputs "Profile", for: [:profile, f.object.profile || f.object.build_profile] do |pf|
pf.input :name
pf.input :second_name
pf.input :middle_name
pf.input :mobile_phone, :as => :phone
pf.input :country, selected: "RU"
pf.input :city
pf.input :region
pf.inputs "Avatar", for:[:image, pf.object.image || pf.object.build_image] do |fpf|
fpf.input :img, :as => :file
end
end
f.inputs "User Perference" do
f.input :admin, type: :boolean
end
f.actions
end
Unfortunately, this code does not work: the form is correctly displayed with Profile and work, but the form is not visible to the Image. How can I fix this?
Unfortunately, I have not found the right solution for this problem, and it is still relevant (I'm not going to close this question, just in case someday it will answer).
But I modeled the behavior close to the desired one.
So, to the User model I added Avatar-interface for the respective object.
def avatar
if self.profile && self.profile.image
self.profile.image.img
else
nil
end
end
def avatar=(arg)
unless self.profile.image
self.profile.create_image(img:arg)
else
self.profile.image.update_attributes(img:arg)
end
self.profile.image
end
def avatar?
if self.profile && self.profile.image
!self.profile.image.img.nil?
else
nil
end
end
In ActiveAdmin added to the avatar permit_params for User.
permit_params ..., :avatar
Finally, in the form of added file fields:
form do |f|
f.semantic_errors *f.object.errors.keys
f.inputs "User Details" do
#Fields for User
end
f.inputs "profile", for: [:profile, f.object.profile || f.object.build_profile] do |pf|
#Fields for profile
end
f.inputs "Avatar" do
f.input :avatar, as: :file
end
f.actions
end
It is worth noting that if you have observed abnormal behavior when the form is submitted, with empty values, then you should pay attention to the parameters for accepts_nested_attributes_for, in particular update_only and reject_if.
I'm still waiting for the normal solution for multiple nested forms in ActiveAdmin

Nested form in activeadmin not saving updates

I have a nested form in ActiveAdmin for these models (a :class_section has_many :class_dates):
class ClassDate < ActiveRecord::Base
belongs_to :class_section
validates :start_time, :presence => true
validates :end_time, :presence => true
end
and
class ClassSection < ActiveRecord::Base
belongs_to :class_course
has_many :class_dates
belongs_to :location
accepts_nested_attributes_for :class_dates
end
Everything seems to be in the right place when I look at the form. However, when I update a class_date, it doesn't save.
ActiveAdmin.register ClassSection do
permit_params :max_students, :min_students, :info, :class_course_id, :location_id
form do |f|
f.inputs "Details" do
f.input :class_course, member_label: :id_num
f.input :min_students, label: "Minunum Students"
f.input :max_students, label: "Maxiumum Students"
f.input :location
end
f.inputs do
f.input :info, label: "Additional Information"
end
f.inputs "Dates" do
f.has_many :class_dates, heading: false do |cd|
cd.input :start_time, :as => :datetime_picker
cd.input :end_time, :as => :datetime_picker
end
end
f.actions
end
index do
column :class_course
column :location
default_actions
end
filter :class_course
filter :location
show do |cs|
attributes_table do
row :class_course do
cs.class_course.id_num + " - " + cs.class_course.name
end
row :location
row :min_students, label: "Minunum Students"
row :max_students, label: "Maxiumum Students"
row :info, label: "Additional Information"
end
panel "Dates" do
attributes_table_for class_section.class_dates do
rows :start_time, :end_time
end
end
active_admin_comments
end
end
Here is the ActiveAdmin file for ClassDates:
ActiveAdmin.register ClassDate, as: "Dates" do
permit_params :start_time, :end_time, :class_section_id
belongs_to :class_section
end
Can you see a reason why it's not saving properly?
UPDATE: I added the following code to the AA and it seems to work now:
controller do
def permitted_params
params.permit!
end
end
Let me know if there is a better solution. Thanks.
UPDATE 2: There is one lingering problem however. I am unable to delete ClassDates using this form.
You need to permit nested parameters, but you should never use params.permit!. It's extremely unsafe. Try this:
ActiveAdmin.register ClassSection do
permit_params :max_students, :min_students, :info, :class_course_id, :location_id,
class_dates_attributes: [ :id, :start_time, :end_time, :_destroy ]
form do |f|
# ...
f.inputs "Dates" do
f.has_many :class_dates, heading: false, allow_destroy: true do |cd|
cd.input :start_time, :as => :datetime_picker
cd.input :end_time, :as => :datetime_picker
end
end
f.actions
end
# ...
end
The configuration (and permitted_params) of your ClassDate admin panel has nothing to do with the permitted parameters within the ClassSection admin panel. Treat them as separate controllers within the app.
Adding the allow_destroy: true option to the has_many call will add a checkbox to the form to allow you to delete a class time upon form submission.

Resources