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
Related
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
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.
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.
I have two model like:
class Employee
field :name
field :login, type: Boolean
has_one :user
end
class User
field :username
field :email
belongs_to :employee
validates_presence_of :username
end
I want to create an user account when create employee if check box of login field is checked. For this my new action of employees controller is:
def index
#employee = Employee.new
#employee.build_user
end
For this my form code is:
<%= simple_form_for(#employee) %>
<%= f.input :login, :as => :boolean, :label => "Create User" %>
<div class="create-user" style="display: none">
<%= f.simple_fields_for :user do |u| %>
<%= render 'user_fields', {f: u} %>
<% end %>
</div>
<button class="btn btn-info">Save Change</button>
<% end %>
and the _user_fields.html.erb is:
<%= f.input :username %>
I want to validate the user model when check_box of :login field is checked. On unchecked condition the form should be submit. What is the better solution.
Maybe you can move your user validation into employer model ?
something like code below should solve your problems
validates_presence_of :username, :if => login?
What do you think?
maybe use validates_associated:
http://guides.rubyonrails.org/active_record_validations_callbacks.html#validates_associated
or delegation + validates presence might also work
delegate :username, to: :user, allow_nil: true
validates :username, presence: true, if: :login
Finally I got its solution:
class Employee
field :name
field :login, type: Boolean
has_one :user
has_one :user, :class_name => "User", :dependent => :destroy
accepts_nested_attributes_for :user, :reject_if => :login_blank
def login_blank
return false if self.login == true
return true if self.login == false
end
end
I'm trying to get started with active admin. I have this models:
class Client < ActiveRecord::Base
has_many :direcctions
validates :empresa, :presence => true
validates :fono, :presence => true
validates :giro, :presence => true
accepts_nested_attributes_for :direccionts
end
class Direction < ActiveRecord::Base
belongs_to :client
has_one :city
accepts_nested_attributes_for :city
end
class City < ActiveRecord::Base
belongs_to :direction
end
In my Activeadmin.register block for Client I have:
ActiveAdmin.register Cliente do
form do |f|
f.inputs do
f.input :empresa
f.input :fono
f.input :giro
end
f.inputs "Direcciones" do
f.has_many :directions do |j|
j.input :direction
# j.inputs "Ciudad" do
# j.has_one :ciudads do |r|
# r.input :city
# end
# end
end
end
f.buttons
end
end
With this i cant add multiple directions to one cliente, but i can't show the inputs to add a city to a Direction... how can i do that?? and this don't work to.. i have also this error when i try to create a client:
unknown attribute: client_id
Thanks in advance...
ActiveAdmin uses Justin French's Formtastic gem, so you can use that DSL directly in your forms, for example:
f.inputs "Direcciones" do
f.semantic_fields_for :directions do |j|
j.input :direction
j.inputs "Ciudad" do
j.semantic_fields_for :ciudads do |r|
r.input :city
end
end
end
end