Add fields to 'new' view in Rails Admin - ruby-on-rails

I would like to add additional fields to the Rails Admin 'new' view for a specific model object, 'User'. These fields would not be attributes on the model itself but instead just fields that I would like users to be able to submit information with in order to calculate another field.
Is this possible?

Add virtual field to your model in rails admin using,
config.model Address do
list do
# virtual field
configure :full_address do
# any configuration
end
fields :full_address, :street, :number #, ...
end
end
Reference - https://github.com/sferik/rails_admin/wiki/Fields#virtual-fields

I'm not entirely familiar with Rails Admin, but you should be able to get what you want with Rails' virtual attributes mechanism.
In your user.rb model file, you need to add an attr_accessor line, listing the symbols you want to assign to your non-model fields, like this:
class User < ActiveRecord::Base
attr_accessor :virtual_field_one, :virtual_field_two
# Remainder of your code
end
You can add fields to the corresponding view that populate those values:
<%= f.text_field :virtual_field_one %>
Then you can add those attributes to the strong parameters method of your users_controller.rb, like this:
class ActivitiesController < ApplicationController
# other code
def user_params
params.require(:activity).permit(:mode_field_one, :mode_field_two, :virtual_field_one, :virtual_field_two)
end
# other code
end
Now you should be able to access virtual_field_one and virtual_field_two from the params hash like any other field in your User model:
virtual_field_one = params[:virtual_field_one]

Related

Want to be able to set the default field values that should be shown in a multi-select list rails_admin

I have the following model
class Campaign < ActiveRecord::Base
has_many :campaign_rules
has_many :campaign_details
validates_presence_of [:start_at, :end_at]
rails_admin do
edit do
field :slug
field :start_at
field :end_at
field :is_active
fields :campaign_rules do
searchable :slug
end
fields :campaign_details
end
end
end
in my view, i get the following when i want to say create a new campaign.
But in my campaign_rules model, i have a field called slug which i would prefer to be shown as the default text in the associated record in the multi-select list. So for example for CampaignRule #1 , slug name is campaign-1 and i would prefer in my multi-select list to show campaign-1 instead of CampaignRule #1.
How can i do this?
I also want to be able to make sure that the multi-select dropdown list shown is based on associated campaign_id. Currently in my multi-select dropdown, it shows all records of the CampaignRule even though there is an association with campaign. How do i configure this as well?
By default rails admin uses the name attribute of an instance to display them.
You can tell rails admin what method to use adding this line on the initializer config file.
RailsAdmin.config {|c| c.label_methods << :rails_admin_title }
And then you would implement that instance method on your tag model
class CampaignRaule < ApplicationRecord
def rails_admin_title
self.slug
end
end
As to how customize the records on the multi-select dropdown you can filter them with a regular ActiveRecord scope like this:
class Campaign < ApplicationRecord
rails_admin do
edit do
field :campaign_rules do
associated_collection_scope do
associated_collection_scope do
campaign = bindings[:object]
proc { |scope| scope.where(campaign: campaign) }
end
end
end
end
end
end

Using strip before field gets saved to databse in ROR

I would like to strip all whitespace in some fields before they go into my database.
I am using devise and have added additional fields to the members table (used members instead of users).
On my sign up form I have some fields such as telephone and address however I would like to strip all whitespace for certain fields like :telephone, :mobile and :emergency_number.
Sounds like a job for before_save!
class Member < ActiveRecord::Base
before_save :strip_whitespace
private
def strip_whitespace
self.telephone.gsub!(/\s+/, '')
# etc...
end
end
An easy way to #Chowlett's solution
class Member < ActiveRecord::Base
before_save :strip_whitespace
private:
def strip_whitespace
self.telephone.join('')
# etc...
end
end

How to create an object of a STI subclass using ActiveAdmin

Given the following setup(which is not working currently)
class Employee < ActiveRecord::Base
end
class Manager < Employee
end
ActiveAdmin.register Employee do
form do |f|
f.input :name
f.input :joining_date
f.input :salary
f.input :type, as: select, collection: Employee.descendants.map(&:name)
end
end
I would like to have a single "new" form for all employees and be able to select the STI type of the employee in the form.
I am able to see the select box for "type" as intended but when I hit the "Create" button, I get the following error:
ActiveModel::MassAssignmentSecurity::Error in Admin::EmployeesController#create
Can't mass-assign protected attributes: type
Now, I am aware of the way protected attributes work in Rails and I have a couple of workarounds such as defining Employee.attributes_protected_by_default but that is lowering the security and too hack-y.
I want to be able to do this using some feature in ActiveAdmin but I can't find one. I do not want to have to create a custom controller action as the example I showed is highly simplified and contrived.
I wish that somehow the controller generated by ActiveAdmin would identify type and do Manager.create instead of Employee.create
Does anyone know a workaround?
You can customize the controller yourself. Read ActiveAdmin Doc on Customizing Controllers. Here is a quick example:
controller do
alias_method :create_user, :create
def create
# do what you need to here
# then call create_user alias
# which calls the original create
create_user
# or do the create yourself and don't
# call create_user
end
end
Newer versions of the inherited_resources gem have a BaseHelpers module. You can override its methods to change how the model is altered, while still maintaining all of the surrounding controller code. It's a little cleaner than alias_method, and they have hooks for all the standard REST actions:
controller do
# overrides InheritedResources::BaseHelpers#create_resource
def create_resource(object)
object.do_some_cool_stuff_and_save
end
# overrides InheritedResources::BaseHelpers#destroy_resource
def destroy_resource(object)
object.soft_delete
end
end

Rails: Using form fields that are unassociated with a model in validations

In a Ruby on Rails application I am trying to use information from fields that are not associated with the model in validation.
Here is part of the model as an example (the whole model has gotten kinda big):
class Scorecard < ActiveRecord::Base
belongs_to :course
belongs_to :user
validate :attributes_consistency
def attributes_consistency
# Executed for all scorecards. Checks if the user completed the hole attributes correctly
if ( params[:no_fairways] and any_fairways? and !only_nine? ) or ( params[:no_fairways] and !any_h1_to_h9_score_blank and any_h1_to_h9_fairway? and only_nine? ) or ( params[:no_fairways] and !any_h10_to_h18_score_blank and any_h10_to_h18_fairway? and only_nine? )
errors.add_to_base("You inidicated that you missed all the fairways, but you also marked one or more fairways in the scorecard. Either uncheck the fairways mistakenly marked or uncheck the 'No fairways' checkbox.")
end
if ( params[:no_girs] and any_girs? and !only_nine? ) or ( params[:no_girs] and !any_h1_to_h9_score_blank and any_h1_to_h9_gir? and only_nine? ) or ( params[:no_girs] and !any_h10_to_h18_score_blank and any_h10_to_h18_gir? and only_nine? )
errors.add_to_base("You inidicated that you missed all the greens, but you also marked one or more greens in the scorecard. Either uncheck the marked greens on the scorecard or uncheck the 'No GIRs' checkbox.")
end
end # attributes_consistency
def any_h1_to_h9_score_blank?
h1_score.blank? or h2_score.blank? or h3_score.blank? or h4_score.blank? or h5_score.blank? or h6_score.blank? or h7_score.blank? or h8_score.blank? or h9_score.blank?
end
def any_h10_to_h18_score_blank?
h10_score.blank? or h11_score.blank? or h12_score.blank? or h13_score.blank? or h14_score.blank? or h15_score.blank? or h16_score.blank? or h17_score.blank? or h18_score.blank?
end
def any_h1_to_h9_fairway?
h1_fairway? or h2_fairway? or h3_fairway? or h4_fairway? or h5_fairway? or h6_fairway? or h7_fairway? or h8_fairway? or h9_fairway?
end
def any_h10_to_h18_fairway?
h10_fairway? or h11_fairway? or h12_fairway? or h13_fairway? or h14_fairway? or h15_fairway? or h16_fairway? or h17_fairway? or h18_fairway?
end
def any_h1_to_h9_gir?
h1_gir? or h2_gir? or h3_gir? or h4_gir? or h5_gir? or h6_gir? or h7_gir? or h8_gir? or h9_gir?
end
def any_h10_to_h18_gir?
h10_gir? or h11_gir? or h12_gir? or h13_gir? or h14_gir? or h15_gir? or h16_gir? or h17_gir? or h18_gir?
end
So how can I access params from the model?
Don't let params sneak up to the model. There's no point of having a controller in that case. Instead, checkout this episode from Railscasts that talks about virtual attributes that do not go into the database but can still be used for validations.
You don't need a corresponding model attribute for the virtual attributes. Define attributes local to the class such as #no_fairways that hold the state.
class ScoreCard < ActiveRecord::Base
# define attributes and accessors for both fields
attr_accessor :no_fairways, :no_girs
..
end
Now inside you form, you could just write:
<% form_for #scorecard %>
<%= f.check_box :no_fairways %>
<% end %>
Found the solution, thanks for the lingo though, "virtual attribute" helped with the google searchin.
The cleanliest way to accomplish this is to create attributes that are not part of the database but still part of the model. In my case I put this into the model:
attr_accessor :no_fairways
attr_accessor :no_girs
That easy! Now #scorecard.no_fairways and #scorecard.no_girs act just like any other attribute but aren't part of the database.

rails arguments to after_save observer

I want users to enter a comma-delimited list of logins on the form, to be notified by email when a new comment/post is created. I don't want to store this list in the database so I would use a form_tag_helper 'text_area_tag' instead of a form helper text_field. I have an 'after_save' observer which should send an email when the comment/post is created. As far as I am aware, the after_save event only takes the model object as the argument, so how do I pass this non model backed list of logins to the observer to be passed on to the Mailer method that uses them in the cc list.
thanks
You want to store the list in a virtual attribute. It will be available in the after_save callback.
I think the better way will be to use a tableless model. Look at Railscatsts screencast for an example. It's pretty simple.
Here are the models you would need (along w/ the form) and the virtual attribute in the user model.
# app/models/user.rb
class User < ActiveRecord::Base
# virutal attribute and validations
attr_accessor :unpersisted_info
validates_presence_of :unpersisted_info
end
# app/models/user_observer.rb
class UserObserver < ActiveRecord::Observer
def after_save(user)
# logic here...
end
end
# form for view...
<%form_for #user do |f|%>
<%= f.text_field :unpersisted_info %>
<%= f.submit "Go" %>
<%end%>

Resources