I am working on a custom form in ActiveAdmin which I decided to use it for adding/editing to follow the DRY principle so I need to populate it if the user uses it for editing a record ( which isn't a DB record ).
So the problem is I have those inputs :
f.input :model_id, as: :select, collection: Model.all.map { |m| [m.id.to_s + ' - ' + m.name, m.id] }, input_html: { required: true }
f.input :enabled, as: :select, collection: {'Yes': true, 'No': false}, input_html: { required: true }
And I'd like to set a default value for them if I'm using the form for editing but I failed to know how because everybody is talking about using belongs_to or a DB relation and ActiveAdmin will take care of the default value for you which isn't applicable for my case because it's not a DB record and I don't have an ActiveRecord Model for it.
Even the official docs of Formtastic didn't help.
I figured out how to do it and here is the answer for anyone facing the same problem :
f.input :model_id, collection: Model.all.map { |m| [m.id.to_s + ' - ' + m.name, m.id] }, selected: object.model_id
f.input :enabled, collection: { 'Yes': true, 'No': false }, selected: object.enabled
Related
We are looking to add a new hidden field into our form but every time I add in a new field (even copy and pasting a field that works and just adding a number to the end) we get an error,
ActionView::Template::Error (undefined method `hidden_gclid' for #<Wizard::Lead::Step2:0x00000004d859d8>):
Please let me know which code you would like to see. I tried reading some documentation here and thought, I might need to add a database column but I'm not sure.
Thank you all for the help and I apologize for the delay. I didn't receive
notification on the comments. I have a new problem though. After getting the new field created we are getting this error,
F, [2019-01-09T05:08:28.887941 #26599] FATAL -- : [437ed38a-c36c-4121-9608-385c43d0449e]
F, [2019-01-09T05:08:28.888395 #26599] FATAL -- : [437ed38a-c36c-4121-9608-385c43d0449e] NameError (undefined local variable or method `hidden_gclid' for #<Lead:0x0000000527c4a0>):
F, [2019-01-09T05:08:28.888449 #26599] FATAL -- : [437ed38a-c36c-4121-9608-385c43d0449e]
F, [2019-01-09T05:08:28.888487 #26599] FATAL -- : [437ed38a-c36c-4121-9608-385c43d0449e] app/models/lead.rb:91:in `sales_force_info'
lead.rb
# This model represents an User's (customer) submission through the form
class Lead < ApplicationRecord
validates :address, :lat, :lng, presence: true
belongs_to :user, optional: true
has_and_belongs_to_many :characteristics
has_many :offers, inverse_of: :lead, dependent: :destroy
scope :newest_first, (-> { order(created_at: :desc) })
enum pool_type: %i[
in_ground above_ground none_or_community
]
enum kitchen_condition: %i[
great_kitchen typical_kitchen needs_work_kitchen
]
enum bathroom_condition: %i[
great_bathroom typical_bathroom needs_work_bathroom
]
enum timeline_to_sell: %i[
asap 2_4_weeks 4_6_weeks few_months just_curious
]
enum looking_for_another: %i[
yes already_found no
]
enum reasons_for_selling: %i[
upgrading relocating downsizing retiring selling_investment
]
enum offer_status: %i[
pending sent accepted declined closed
]
attr_accessor :hidden_gclid
def has_basic_information?
if bedrooms.present? || bathrooms.present? ||
built_surface.present? || pool_type.present? ||
kitchen_condition.present? || bathroom_condition.present? ||
renovated.present? || renovated_spent.present? ||
renovated_description.present?
return true
end
false
end
def street
(address.remove(', USA')&.split(",").count == 3) ? address.remove(', USA')&.split(",").first : "#{address.remove(', USA')&.split(",").first}, #{address.remove(', USA')&.split(",").second}"
end
def city
address.remove(', USA')&.split(",").second_to_last
end
def state_code
address.remove(', USA')&.split(",").last
end
def sales_force_info
form = { 'oid' => 'xxxxxx', # roganization id
'retURL' => 'http://placeholder.com',
'00No0000009e5Lb' => 'Cash Offer',
'country_code' => 'US',
'first_name' => user&.first_name,
'last_name' => user&.last_name,
'phone' => user&.phone,
'street' => street, #address
'city' => city,
'state_code' => state_code,
'zip' => zip,
'description' => "Check more lead info at www.placeholder.com/leads/#{id}",
'email' => user&.email,
'lead_source' => user&.how_about_us || "Web",
'00N1N00000Oko3t' => bedrooms,
'00N1N00000Oko3y' => bathrooms,
'00N1N00000Oko43' => built_surface,
'00N1N00000Oko48' => air_conditioner,
'00N1N00000Oko4N' => roof_age,
'00N1N00000Oko4h' => timeline_to_sell,
'00N1N00000Oko4m' => looking_for_another,
'00N1N00000Oko4r' => reasons_for_selling,
'00N1N00000Oko4S' => renovated,
'00N1N00000Oko4X' => renovated_spent,
'00N1N00000Oko4c' => renovated_description,
'00N1N00000Oko4w' => own_valuation,
'00N1N00000PMKAo' => hidden_gclid
}
form
end
def send_info_to_sales_force
puts "SENDING INFO TO SALES FORCE!"
url = URI('https://webto.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8')
form = sales_force_info
res = Net::HTTP.post_form(url, form)
puts res.body
end
end
form
:javascript
window.onload = function getGclid() {
document.getElementById("00N1N00000PMKAo").value = (name = new RegExp('(?:^|;\\s*)gclid=([^;]*)').exec(document.cookie)) ? name.split(",")[1] : ""; }
.block.block-fill-height.px-0
= render 'application/header', logo: 'logo-blue.png'
.container.mt-2.pt-5
.card.card-outline-primary
%h3.card-header
%ul.nav.nav-bordered
%li.nav-item
%a.nav-link{:href => "#"} Basics
%li.nav-item
%a.nav-link.active{:href => "#"} Sale
%li.nav-item
%a.nav-link{:href => "#"} Offer
.card-block
%h4.card-title Where should we send your offer?
%p.card-text
%strong Save your progress
and join thousands of home owners who work with us every month.
%hr
%h5.mt-5 Create your account below:
= simple_form_for User.new, url: '/users', method: 'POST', html: { class:'mt-4' } do |f|
.form-group
= f.label(:phone, 'Phone')
= f.input_field(:phone, class: 'form-control', placeholder: 'Phone', required: true)
.form-group
= f.label(:first_name, 'First Name')
= f.input_field(:first_name, class: 'form-control', placeholder: 'First Name')
.form-group
= f.label(:last_name, 'Last Name')
= f.input_field(:last_name, class: 'form-control', placeholder: 'Last Name')
.form-group
= f.label(:email, 'Email')
= f.input_field(:email, class: 'form-control', placeholder: 'Enter your Email')
.form-group
= f.label(:password, 'Password')
= f.input_field(:password, class: 'form-control', placeholder: '6 characters minimum')
.form-group
= f.label(:how_about_us, 'Where did you hear about us?')
%br
= f.select :how_about_us, ['TV Commercial', 'Word of Mouth', 'Radio', 'Web', 'Letter/Postcard/Doorhanger',
'Social Media', 'Telephone Call'], class: 'form-control', prompt: 'Please Select', required: true
%hr
= hidden_field_tag(:hidden_gclid, "", :id => "00N1N00000PMKAo")
= hidden_field_tag(:current_step, 'step3')
= f.submit 'Next', class: 'btn btn-success btn-lg'
It looks like we have the form going without any errors now but we need the hidden field ID 00N1N00000PMKAo to send to salesforce but it isn't.
Since simple_form relies on the model instance you have two options here:
add a database column to the corresponding table
use a virtual attribute
Looks like you don't want to store the value in the db, in this case just add attr_accessor :hidden_gclid to your model. After it you can use it like a normal attribute inside the controller action.
I use select2 for multiple select. My problem is, I can select multiple value from json data and I can save this data in related model columns. But when I want to update this model, the selected data doesn't appear.
some part of my json data:
{
- categories:[
- {
id:7,
name:"Eğitim Bilimleri Enstitüsü"
},
- {
id: 8,
name: "Eğitim Yönetim Teftişi ve Planlaması 1. Yarıyıl"
},
...
]
}
I have a Moodle class(it is not inheritance from ActiveRecord, just a class and it has some functions which return json data). I am wondering whether it is right approach.
in the content of my form:
<%= simple_form_for(#period) do |f| %>
...
<%= f.input :moodle_connect_ids, collection: Moodle.categories.map {|p| [ p['name'], p['id'] ] }, input_html: {multiple: true} %>
...
<% end %>
I explicitly set moodle_connect_ids to be an array in my controller:
params.require(:period).permit(..., :moodle_connect_ids => [])
in the content of my .js file:
$("#period_moodle_connect_ids").select2({
placeholder: "Moodle Dönem Bağlantılarını Seçiniz",
multiple: true,
allowClear: true
});
When I select to multiple values and save my model, the column's value looks like this:
> Period.last
=> #<Period:0x007fcf53a4d830
id: 25,
...
moodle_connect_ids: "[\"\", \"85\", \"120\"]"
...
Am I on the wrong way? Have you any suggestion?
I've figured out how to do this issue.
I've added selected option in the f.input:
selected: #period.moodle_connect_ids? ? JSON.parse(#period.moodle_connect_ids).map(&:to_i) : []
the input's last state:
<%= f.input :moodle_connect_ids, collection: Moodle.categories.map {|p| [ p['name'], p['id'] ] }, input_html: {multiple: true}, selected: #period.moodle_connect_ids? ? #period.moodle_connect_ids.map(&:to_i) : [] %>
I have the following form but for some reason, I can't get the HTML class to come appear in the resulting code. The documentation suggests this should work, but they don't have an example that uses a block. I've tried a few different things but I haven't found the right answer yet. I have to use a block to get the custom data to appear with the select.
= simple_form_for([:admin, #theme]) do |f|
= f.input :title_bar
= f.input :apple_touch_icon_image, input_html: { class: 'imagepicker' } do
= f.select :apple_touch_icon_image_id, Theme::AppleTouchIconImage.where(company: #company).map{ |i| [i.id, i.id, { 'data-img-src' => i.image.url(:thumbnail) }] }
= f.button :submit, class: "btn-success"
I would try:
= f.input :apple_touch_icon_image do
= f.select :apple_touch_icon_image_id, Theme::AppleTouchIconImage.where(company: #company).map{ |i| [i.id, i.id, { 'data-img-src' => i.image.url(:thumbnail) }] }, {}, { class: 'imagepicker' }
I have edited my first code and now it's better and cleaner thanks to #FunTimeFreddie, but the issue it's not yet properly solved. I'll come back with the right answer sooner.
In a search form I need to filter all menuitems:
1. per category
2. per category and search “query”
3. per min price && || max price
… and so on, with all possible combinations
I’ve manage to make a search in all menuitems with a “query”, min_price and max_price --all possible combinations from the search form. I can NOT manage to have the list of results of the chosen category, what am I doing wrong?
This is my model(edited):
class Menuitem < ActiveRecord::Base
belongs_to :menu_category
include Filterable
scope :newest_first, lambda { order('menuitems.created_at DESC') }
scope :last_one, lambda { order('menuitems.created_at ASC').last }
scope :search_keyword, lambda { |query|
where(["title LIKE ? or body LIKE ?", "%#{query}%", "%#{query}%"]) if query != ""
}
scope :menu_category_id, lambda { |menu_category_id|
where( "menu_category_id = ?", menu_category_id ) if menu_category_id != ""
}
scope :min_price, lambda { |price|
where("price > ?", price) if price != ""
}
scope :max_price, lambda { |price|
where("price < ?", price) if price != ""
}
end
This is my controller(edited):
class MenuitemsController < ApplicationController
def index
#menuitems = Menuitem.newest_first.filter(params.slice(:menu_category_id, :search_keyword, :min_price, :max_price))
end
And this is my view:
<%= simple_form_for :menuitem, :method => 'get', :url => {:action => 'index'} do |f| %>
<p>
<%= f.select :menu_category_id, options_for_select(#menucategories.map {|s| [s.title, s.id]}, params[:menu_category_id]), :selected => params[:menu_category_id], :onchange => "this.form.submit();", prompt: "Select category" %>
</p>
<p>
<%= f.input :search_keyword, input_html: { name: 'search_keyword', :value => params[:search_keyword]}, label: 'search recipe title', :required => false %>
<%= f.input :min_price, input_html: { name: 'min_price', :value => params[:min_price]}, label: 'min price:', :required => false %>
<%= f.input :max_price, input_html: { name: 'max_price', :value => params[:max_price]}, label: 'max price:', :required => false %>
<%= f.button :submit, "search" %>
</p>
<% end %>
You can save yourself the trouble of all the IF statements in your controller for all of the combinations by adding an IF statement within the scopes. For example, and this can similarly be applied to the four scopes associated to your form,
# menuitem model
scope :search_keyword, lambda { |query|
where(["name LIKE ?", "%#{query}%"]) if query != ""
}
This will allow to include only a single line in your controller, the line beneath your first IF statement, as this will handle the blank parameters.
There seems to be two issues with the category parameter. The first is it is a nested parameter within params[:menuitem], so in order to access it we need to call params[:menuitem][:menu_category_id]. Not too sure why this is happening to be honest, though I would recommend in this instance using a form_tag as opposed to form_for, given that we are not adding or editing the menuitems table itself.
The second issue is the category parameter is passed as a string, whereas we need it as an integer. We'll need to convert to parameter before applying it.
Now I'm not familiar with the .filters method (is this part of a gem?) but I got this to work the old fashioned way just by concatenating all the scopes together in one line as follows...
# menuitems controller
def index
#menuitems = Menuitem.newest_first.min_price(params[:min_price]).max_price(params[:max_price]).search_keyword(params[:search_keyword]).menu_category_id(params[:menuitem][:menu_category_id].to_i)
end
Note, another way of changing the data type would be to do so in the scope. You could do this as follows
# menuitem model
scope :menu_category_id, lambda { |menu_category_id|
where( "menu_category_id = ?", menu_category_id.to_i ) if menu_category_id != ""
}
<%= collection_select(:catgory, :id, #categories, :id, :title, {}, data: { behavior: 'category_dropdown' }) %>
In the above code I need to pass a parameter to the title method. Is there any way to do this with collection_select?
<%= collection_select(:catgory, :id, #categories, :id, (:title, #program), {}, data: { behavior: 'category_dropdown' }) %>
Edit:
Looking at the internals for collection_select the text_method. It is eventually passed to a .send method which should allow for element.send(:title, #program). However, I think the issue why I still can't pass the param is that collection select is reading (:title, #program) as two params instead of one.
Use select instead:
select "catgory", "id", #categories.map{|c| [c.title(#program), c.id]}, {}, data: { behavior: 'category_dropdown' }
Should be working.
This can be done with collection_select if your model has an existing parameter you can overwrite:
f.collection_select( :your_model_id,
YourModel.all.map{|ym| ym.name = ym.custom_name(your_parameter); ym},
:id, :name,
{:selected => #model_instance.logic},
{:class => 'your class', :other => "..." } )
For instance I do this to conditionally pluralize my model's name attribute
class MyModel < ActiveRecord::Base
DEFAULT_NAME_COUNT = 99
def pluralized_name(n = DEFAULT_NAME_COUNT)
begin
return name.pluralize(n)
rescue
end
name
end
end