I have a model with self-referential has_many relation though another model.
So I have model Product and each product can have another products.
class Project < ActiveRecord::Base
has_many :project_connections
has_many :related_projects, through: :project_connections,
dependent: :destroy
accepts_nested_attributes_for :project_connections,
:related_projects, allow_destroy: true
...
end
and my ProjectConnection model:
class ProjectConnection < ActiveRecord::Base
belongs_to :project
belongs_to :related_project, class_name: Project
accepts_nested_attributes_for :project
accepts_nested_attributes_for :related_project
...
end
In Active Admin I want in create/edit project view to remove or add related_project.
In admin/project.rb
form do |f|
inputs 'Продолжение проекта' do
f.has_many :related_projects, heading: 'Добавьте проект', allow_destroy: true, new_record: true do |i|
i.input :id, as: :select, collection: Project.all, include_blank: false
end
end
end
http://localhost:3000/admin/projects/1/edit
After I add new related_project and press Update Project, nothing was changed.
So what should I do to fix that? Thanks.
A possible solution would be to have a abstract field on the project, connected_project_ids, and a before_save filter to persist the changes, and an after load to fill the field for initializing the form
before_save :connect_projects
after_find :set_connected_project_ids
attr_accessor :connected_project_ids
def set_connected_project_ids
self.connected_project_ids = connected_projects.pluck(:related_project_id)
end
def connect_projects
connected_ids = connected_projects.pluck(:related_project_id)
#projects that are in connected_project_ids, but not yet associated
projects_to_connect = connected_project_ids - connected_ids
projects_to_connect.each do |cp_id|
connected_projects.create(related_project_id: cp_id)
end
#projects that are associated, but not in connected_project_ids
projects_to_disconnect = connected_ids - connected_project_ids
projects_to_disconnect.each do |cp_id|
connected_projects.where(related_project_id: cp_id).destroy_all
connected_ids
end
this would allow you to add and remove associated projects by submitting the array of project ids it should now be associated with in the connected_project_ids field.
So, I solved problem by myself. As ProjectConnection store connections between projects {id, project_id, related_project_id}, it would be correct to manipulate with projects.project_connections, not projects.related_projects. First, I declared a structure of params for projects.project_connections in admin/project.rb:
project_connections_attributes: [
:id,
:project_id,
:related_project_id,
:_destroy
]
Then instead of
inputs 'Продолжение проекта' do
f.has_many :related_projects, heading: 'Добавьте проект', allow_destroy: true, new_record: true do |i|
i.input :id, as: :select, collection: Project.all, include_blank: false
end
end
I wrote
inputs 'Продолжение проекта' do
f.has_many :project_connections, heading: 'Добавьте проект', allow_destroy: true, new_record: true do |i|
i.input :related_project_id, as: :select, collection: Project.all, include_blank: false
i.input :project_id, :input_html => { :value => f.object.id }, as: :hidden
end
end
It works perfectly)
Related
I've seen many similar questions to this one, but none that quite answer it. I have a form that has an input for a join model. I've successfully created several of these with single inputs, but I'm trying to create one in which the user can select multiple from a dropdown of the associated record and create join records for each one selected. It's not working, and it appears the params are trying to assign all of the associated model ids to a single join record.
class AdminUser < ApplicationRecord
has_many :admin_locations, dependent: :destroy
has_many :locations, through: :admin_locations
end
class AdminLocation < ApplicationRecord
belongs_to :admin_user
belongs_to :location
end
class Location < ApplicationRecord
has_many :admin_locations, dependent: :destroy
has_many :admin_users, through: :admin_locations
end
#in the admin_users edit form
f.has_many :admin_locations,
allow_destroy: true do |l|
l.input :location_id,
as: :select,
include_hidden: false,
multiple: true,
collection: locs
#in admin/admin_user permitted params
admin_location_ids: [],
admin_locations_attributes: [:id, :location_id, :admin_user_id, :_destroy, :_create, :_update]
I've permitted all the params through the admin/ file, but I'm still getting the error on rollback that location_id is not a permitted param in the admin_locations form. The params show that all selected ids are getting assigned to a single join record: "admin_locations_attributes"=>{"0"=>{"location_id"=>["236", "238", "239", "241"]}}} Is there any way to make this work?
Oh, wow, thanks Ryan Bates. Found a decade old rails cast that answered this. I was over-complicating it.
this works:
f.input :locations,
allow_destroy: true,
as: :select,
include_hidden: false,
multiple: true,
collection: locs
No need for the join nesting in the form.
I have three models:
class Request < ActiveRecord::Base
belongs_to :scenario
belongs_to :location
has_many :actions, :foreign_key => 'request_id'
accepts_nested_attributes_for :actions, :allow_destroy => true
end
class Action < ActiveRecord::Base
belongs_to :request
belongs_to :scenario_step
end
class ScenarioStep < ActiveRecord::Base
belongs_to :scenario
has_many :actions
end
Using Active Admin I want to update information about action taken in response to a request. To do that I am using nested form:
ActiveAdmin.register Request do
permit_params :scenario_id, :location_id,
actions_attributes: [:scenario_step_id, :description]
form(:html => {:multipart => true}) do |f|
f.inputs "Request details" do
f.input :status
panel 'Steps' do
"Text ..."
end
f.has_many :actions, heading: 'Steps to follow', allow_destroy: false, new_record: true do |ff|
ff.input :description, label: ff.object.scenario_step_id, hint: 'Text'
ff.input :scenario_step_id
end
para "Press cancel to return to the list without saving."
f.actions
end
end
end
Everything seems to be fine except of label (or hint). As a value I want to put there related data from a table scenario_steps.
As you can see I currently try to at least print the value of scenario_step_id that should be available in the object form (ff.object.scenario_step_id) but it is not working (I have such column in actions table). On the other hand, next line: ff.input :scenario_step_id loads appropriate data into input field.
Can somebody give ma a hint what am I doing wrong?
Here is what I was missing (part of formtastic documentation):
Values for labels/hints/actions are can take values: String (explicit
value), Symbol (i18n-lookup-key relative to the current "type", e.g.
actions:), true (force I18n lookup), false (force no I18n lookup).
Titles (legends) can only take: String and Symbol - true/false have no
meaning.
So small change (to_s) in line below makes huge difference :)
ff.input :description, label: ff.object.scenario_step_id.to_s, hint: 'Text'
In my app, Invoice has_many Item. So in my active admin UI, I want to be able to create a invoice, and at the same time create its items.
But I can only add items after the invoice is created using the Edit Invoice button in active admin. Trying to create them together will not direct me anywhere from the New Invoice page. And there aren't any errors shown. Could someone help me out on this?
I have the following form structure in my app/admin/invoice.rb
permit_params :paid, :due, :customer_id,
items_attributes: [:price, :description, :invoice_id, :purchased_product_id]
form multipart: true do |f|
f.inputs do
input :customer
input :due
input :paid, as: :radio
end
f.inputs "Items" do
f.has_many :items do |item|
item.input :price
item.input :description
item.input :purchased_product
end
end
f.actions
end
I have added the accepts_nested_attributes_for in my Invoice model as follow:
class Invoice < ActiveRecord::Base
belongs_to :customer
has_many :items
accepts_nested_attributes_for :items, allow_destroy: true
validates :customer, presence: true
I am using Rails 4, and activeadmin '~> 1.0.0.pre1'
The problem is to deal with my validations in my Item model. I had the following validation rule in my Item model class
validates :price, :invoice, presence: true
This says that in order to create an item, it has to have an invoice connected. But since in the creation process of the invoice and its contained items, invoice is yet saved to database. The items can't find an invoice to connect to yet, and the validation failed.
The problem is solved by removing the presence validation of invoice, to
validates :price, presence: true
I have the models Home and Photo, which have a has_many - belongs_to relationship (a polymorphic relationship, but I dont think that matters in this case). I am now setting up active admin and I would like admins to be able to add photos to homes from the homes form.
The photos are managed by the CarrierWave gem, which I dont know if will make the problem easier or harder.
How can I include form fields for a different model in the Active Admin Home form? Any experience doing something like this?
class Home < ActiveRecord::Base
validates :name, :presence => true,
:length => { :maximum => 100 }
validates :description, :presence => true
has_many :photos, :as => :photographable
end
class Photo < ActiveRecord::Base
belongs_to :photographable, :polymorphic => true
mount_uploader :image, ImageUploader
end
Try something like this in app/admin/home.rb:
form do |f|
f.inputs "Details" do
f.name
end
f.has_many :photos do |photo|
photo.inputs "Photos" do
photo.input :field_name
#repeat as necessary for all fields
end
end
end
Make sure to have this in your home model:
accepts_nested_attributes_for :photos
I modified this from another stack overflow question: How to use ActiveAdmin on models using has_many through association?
You could try this:
form do |f|
f.semantic_errors # shows errors on :base
f.inputs # builds an input field for every attribute
f.inputs 'Photos' do
f.has_many :photos, new_record: false do |p|
p.input :field_name
# or maybe even
p.input :id, label: 'Photo Name', as: :select, collection: Photo.all
end
end
f.actions # adds the 'Submit' and 'Cancel' buttons
end
Also, you can look at https://github.com/activeadmin/activeadmin/blob/master/docs/5-forms.md (See Nested Resources)
I guess you are looking for a form for a nested model. Take a look at following railscasts.
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
I cannot tell you much about active_admin, but I think this should not make a difference in handling the nested model.
I have a has_one model, like this:
f.has_many :addresses do |a|
a.inputs "Address" do
a.input :street ... etc.
While this correctly reflects our associations for Address (which is a polymorphic model) using f.has_one fails. So I changed over to has_many and all's well. Except now we have to prevent our users from creating multiple addresses for the same entity.
We are using active_admin for our administration backend.
We have a model "App" that :belongs_to model "Publisher":
class App < ActiveRecord::Base
belongs_to :publisher
end
class Publisher < ActiveRecord::Base
has_many :apps
end
When creating a new entry for the "App" model I want to have the option to either select an existing publisher or (if the publisher is not yet created) to create a new publisher in the same (nested) form (or at least without leaving the page).
Is there a way to do this in active_admin?
Here's what we have so far (in admin/app.rb):
form :html => { :enctype => "multipart/form-data" } do |f|
f.inputs do
f.input :title
...
end
f.inputs do
f.semantic_fields_for :publisher do |p| # this is for has_many assocs, right?
p.input :name
end
end
f.buttons
end
After hours of searching, I'd appreciate any hint... Thanks!
First, make sure that in your Publisher model you have the right permissions for the associated object:
class App < ActiveRecord::Base
attr_accessible :publisher_attributes
belongs_to :publisher
accepts_nested_attributes_for :publisher, reject_if: :all_blank
end
Then in your ActiveAdmin file:
form do |f|
f.inputs do
f.input :title
# ...
end
f.inputs do
# Output the collection to select from the existing publishers
f.input :publisher # It's that simple :)
# Then the form to create a new one
f.object.publisher.build # Needed to create the new instance
f.semantic_fields_for :publisher do |p|
p.input :name
end
end
f.buttons
end
I'm using a slightly different setup in my app (a has_and_belongs_to_many relationship instead), but I managed to get it working for me. Let me know if this code outputs any errors.
The form_builder class supports a method called has_many.
f.inputs do
f.has_many :publisher do |p|
p.input :name
end
end
That should do the job.
Update: I re-read your question and this only allows to add a new publisher, I am not sure how to have a select or create though.
According to ActiveAdmin: http://activeadmin.info/docs/5-forms.html
You just need to do as below:
f.input :publisher
I've found you need to do 3 things.
Add semantic fields for the form
f.semantic_fields_for :publisher do |j|
j.input :name
end
Add a nested_belongs_to statement to the controller
controller do
nested_belongs_to :publisher, optional: true
end
Update your permitted parameters on the controller to accept the parameters, using the keyword attributes
permit_params publisher_attributes:[:id, :name]