Rails 3. How to add a helper that ActiveAdmin will use? - ruby-on-rails

I'm creating a helper to be used by Formtastic but I get the undefined local variable or method error. I don't know where to put it so it can work.
I already tried in the application_helper.rb and in app/helpers/active_admin/view_helpers.rb

You can define them in app/helpers/ as you tried but you need to include them trough the active admin's initializer like this:
# in config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
....
end
module ActiveAdmin::ViewHelpers
include ApplicationHelper
end

You need to put your helper functions in app/helpers/active_admin/views_helper.rb file
Example:
module ActiveAdmin::ViewsHelper #camelized file name
def my_helper
# do something
end
end

What I have found using ActiveAdmin 0.6.1 is that ActiveAdmin will look for helpers in app/helpers/active_admin/*_helper.rb, but the name doesn't really matter.
What does matter is:
the filename must end in "_helper.rb"
the module name must be the camel-case of the file name
the file must be in app/helpers/active_admin/ directory.
If anyone knows where this is officially documented, that would be awesome.
Here is an example: https://gist.github.com/afred/7035a657e8ec5ec08d3b

app/helpers/active_admin/view_helpers.rb
didn't help me
EDITED: i changed it to views_helper.rb & ViewsHelper accordingly and it worked
*but if you want to define it only for certain resource, you can do it in my way
i had to define
#app/helpers/active_admin/categories_helper.rb
module ActiveAdmin::CategoriesHelper
def helper_method
end
end
for my active_admin resource app/admin/categories.rb

Another way to do this is to make the specific ActiveAdmin controller generated behind-the-scenes include the helper. This method will allow making the inclusion of the helpers explicit per file rather than global.
ActiveAdmin.register MyModel do
controller do
include MyHelper
end
end

I can make it work in ActiveAdmin 0.6.1 (finally!). The solution is to create a helper module as following:
# app/helpers/active_admin_helpers.rb
module ActiveAdminHelpers
# make this method public (compulsory)
def self.included(dsl)
# nothing ...
end
# define helper methods here ...
def helper_method
...
end
end
then include this module this way:
# app/admin/[resource].rb
include ActiveAdminHelpers
ActiveAdmin.register [Resource] do
...
end
Actually, it's not a nice solution but it's DRY and working good. I have already read and tried a lot of methods and solutions such as ViewHelpers module (put under 'app/helpers' or 'app/admin/active_admin'), ActiveAdmin::DSL monkey patching, ... but those never worked in version 0.6.1 (I don't have any ideas about other versions) :(

Defining ActiveAdmin::ViewHelpers in app/admin/active_admin/view_helpers.rb works for me with activeadmin 0.3.4 and 0.5.0.

Using activeadmin 1.0.0.pre1 from git://github.com/activeadmin/activeadmin.git
Rails 4.2.1
This worked for me...
my_app/app/helpers/active_admin/resources_helper.rb
module ActiveAdmin
module ResourcesHelper
def resource_form_for(_resource, _params, _options = {}, &_block)
url = if _resource.new_record?
UrlBuilder.resources_path(_resource.class, _params)
else
UrlBuilder.resource_path(_resource.class, _params)
end
method = _resource.new_record? ? :post : :put
options = { url: url, method: method, builder: ActiveAdmin::FormBuilder }
options.merge!(_options)
semantic_form_for([:admin, _resource], options) do |f|
_block.call(f)
end
end
end
end
my_app/app/admin/balance_sheets.rb
ActiveAdmin.register BalanceSheet do
form partial: 'form'
end
my_app/app/views/admin/balance_sheets/_form.html.erb
<%= resource_form_for(resource, params) do |f| %>
<%= f.inputs "Fields" do %>
<%= f.input :progress_status %>
<%= f.input :crew %>
<%= f.input :shift %>
<%= f.input :expected_progress %>
<%= f.input :real_progress %>
<%= f.input :analyst, collection: User.analysts %>
<%= f.input :activity_ids, as: :check_boxes, collection: Activity.balance_sheet_activities %>
<%= f.input :worker_ids, as: :check_boxes, collection: Worker.all %>
<% end %>
<%= f.actions %>
<% end %>

You can also use ActiveAdmin partials :
render partial: 'admin/my_partial', locals: { var: my_var }
And inside app/views/admin/_my_partial.html.arb your active_admin ruby code.

What worked for me with Rails 3.2.11 and and gem activeadmin (0.5.1) was not adding the app/active_admin/view_helpers.rb file, or declaring any modules in config/initializers/active_admin.rb
I put my helpers logically, by model, into the app/*_helpers.rb files. Then inside the app/admin/model.rb file I used:
# app/admin/[resource].rb
ActiveAdmin.register [Resource] do
...
filter :gender, as: :select, collection: proc{genders}
...
end
To use the helper in filters, to display a drop down list of genders to filter on, in the list view. For the corresponding create form fields, I used:
# app/admin/[resource].rb
ActiveAdmin.register [Resource] do
form do |f|
f.inputs "Case Manager" do
...
f.input :gender, as: :radio, collection: genders
...
f.buttons
end
end
end
To display radio buttons for the input form.
Not sure why the proc{} is required outside of the form do |f| block, but if anyone can explain why it's a bad idea, I'll find a different way.

Related

How to make value attribute in the select option tag to have url's in rails

I want value attribute in the select option menu to contain url's and on click should take to the particular path.I am using helper method to build the path
Code:
<%= select_tag :account, options_from_collection_for_select(Account.all,build_path_for_airline(id),"name") %>
helper:
def build_path_for_airline(id)
new_path = Rails.application.routes.recognize_path(request.path)
new_path[:airline_id] = id
new_path
end
Unfortunately its not working as expected, Can anyone let me know what I am missing here?
According to the documentation, the value_method parameter is exactly that, a method. You can't use an arbitrary block of code and expect it to work.
You should implement your build_path_for_airline as an helper method in your model class, and use that method in the options_from_collection_for_select call.
# app/models/account.rb
class Account
# ...
def airline_path
# Build the airline path for the current account
end
end
# app/views/...
<%= select_tag :account, options_from_collection_for_select(Account.all, :airline_path, :name) %>
Richard-Degenne's answer is correct, but there's an alternative to putting the method in your model. options_from_collection_for_select can also take a lambda for its value_method argument:
<%= select_tag :account, options_from_collection_for_select(
Account.all,
->(account){ build_path_for_airline(account.id) },
"name")
%>

Saving custom attribute to Order model in Spree eCommerce

I have added a custom field in my spree_orders table (let's call it custom_attribute).
I have added Spree::PermittedAttributes.checkout_attributes << [:custom_attribute] to my spree.rb initializer.
In my checkout process I have a custom form with the following code (html formatting has been removed):
<%= form_for #order do |alt_form| %>
<%= alt_form.label :custom_attribute, "Custom Attribute" %><span class="required">*</span><br />
<%= alt_form.text_field :custom_attribute, :class => 'form-control required', maxlength: 11 %>
<% end %>
This form successfully submits the field in the post request (full dump below) to http://localhost:3000/checkout/update/address as order[custom_attribute] xyz, however, the information is not saved to the model.
_method=patch
_method=patch
authenticity_token=Y+ATRotWKfI57f+b0/YGwIw9Bg6mADHBDmeEOHYzLPnB6Vbydya4ITDTopcX65EG+TiL7bwyJKQPpBU9bQTaUg==
authenticity_token=Y+ATRotWKfI57f+b0/YGwIw9Bg6mADHBDmeEOHYzLPnB6Vbydya4ITDTopcX65EG+TiL7bwyJKQPpBU9bQTaUg==
commit=Save and Continue
order[bill_address_attributes][address1]=123 Test
order[bill_address_attributes][address2]=
order[bill_address_attributes][city]=Test
order[bill_address_attributes][country_id]=232
order[bill_address_attributes][firstname]=Test
order[bill_address_attributes][id]=3
order[bill_address_attributes][lastname]=Test
order[bill_address_attributes][phone]=555555555
order[bill_address_attributes][state_id]=3535
order[bill_address_attributes][zipcode]=30024
order[email]=spree#example.com
order[custom_attribute]=2414
order[state_lock_version]=32
utf8=✓
utf8=✓
I've inserted #order.inspect on the following (payment) page to can see at that point that #order.custom_attribute is still nil.
Does anyone have any idea about what I need to do in order to get the custom_attribute value sent in the post request saved to the model with the other attributes sent?
-------------------edit-------------------
Default spree permitted attributes are defined here https://github.com/spree/spree/blob/3-0-stable/core/lib/spree/core/controller_helpers/strong_parameters.rb and are added on by the strong_paramaters helper here (don't have the rep to post a third link):
module Spree
module Core
module ControllerHelpers
module StrongParameters
def permitted_attributes
Spree::PermittedAttributes
end
delegate *Spree::PermittedAttributes::ATTRIBUTES,
to: :permitted_attributes,
prefix: :permitted
def permitted_payment_attributes
permitted_attributes.payment_attributes + [
source_attributes: permitted_source_attributes
]
end
def permitted_checkout_attributes
permitted_attributes.checkout_attributes + [
bill_address_attributes: permitted_address_attributes,
ship_address_attributes: permitted_address_attributes,
payments_attributes: permitted_payment_attributes,
shipments_attributes: permitted_shipment_attributes
]
end
def permitted_order_attributes
permitted_checkout_attributes + [
line_items_attributes: permitted_line_item_attributes
]
end
def permitted_product_attributes
permitted_attributes.product_attributes + [
product_properties_attributes: permitted_product_properties_attributes
]
end
end
end
end
end
which can be at found spree/core/lib/spree/core/controller_helpers/strong_parameters.rb in the spree github repo.
-------------------final edit-------------------
If anyone finds this in the future and is trying to troubleshoot a similar issue, my code above is actually correct; I had (stupidly) placed it in an if Rails.env.production? block.
I will give you an example, maybe you can translate it into your code.
OPTIONAL
Imagine that I have a custom action, called "custom" on my users controller, defined this way in my routes:
resources :users do
collection do
get 'custom'
post 'custom'
end
end
This way I can call it by using custom_users_path.
Next, I want a form that submits to that function, to do that you need to specify an additional parameter in your form_for called :url, in this example I call it using custom_users_path, once I submit the form, It will run my custom action.
form_for would look like this:
<%= form_for :user, :url => custom_users_path do |f| %>
<%= f.text_field :random %>
<%= f.submit "Submit" %>
<% end %>
Then, I want to be able to access some :random parameter in my users controller. Let's suppose that I have a text_field which I want store the value on my :random parameter (see above). First, you need to permit that parameter to be accessible in your controller, in this example, in users controller. This way:
params.require(:user).permit(YOUR PARAMETER HERE, {:random => []})
So, every time I submit the form, I can access the :submit parameter value, by doing this params["controller-name"]["parameter-name"], translated into this example, would look like:
params["user"]["random"]
You can then convert it into string using to_s if you want.
Output (Supposing that I wrote "444" on my text_field):
444
I hope this helps you.

run config-block inside formtastic or simple_form

How can I call and run a predefined config-block with formtastic or simple_form elements: What I did so far:
Create the form-config (in this case with formtastic):
AppmeConfig.register App do
form do |f|
f.inputs "Details" do
f.input :category
f.input :slug
end
f.action :submit
end
end
Assign the Block to the template:
def form &block
#form = block
end
In the template i do the following:
=semantic_form_for(#resource, &#form)
Everything fine so far and the source runs ... but it only outputs the last element (in this case the action button). Can you give me a hint, what's wrong?
More Information: the output is exactly the same for formtastic and simple_form, it doesn't work as well with a normal .html.erb-template instead of .haml
Not that nice as expected, but for the first I came up this solution (ok sorry, it's a dirty hack):
=simple_form_for #resource do |f|
- #form.to_source(:strip_enclosure => true).to_s.split("\n").each do |line|
= eval(line)
Explanation of the code above: I used sourcify to parse the whole block and eval it in the context of the form.
The main-problem I found is with the build in form_for-helper of rails, that doesn't accept block input. I'm wrong?

Use ActiveAdmin to edit a single record

I have a model that needs editing that is associated with the current user called BillingProfile. How can I add a menu item that links to the edit page of the current user's BillingProfile? I don't want or need an index page for the BillingProfile as a user can only edit their own.
class User
has_one :billing_profile
end
You can use Cancan to manage the ability to allow a User to edit his own Billing Profile.
ability.rb
...
cannot :edit_billing_profile, User do |u|
u.user_id != user.id
end
...
admin/users.rb
ActiveAdmin.register User do
action_item :only => :show do
link_to "Edit BP", edit_bp_path(user.id) if can? :edit_billing_profile, user
end
end
Or you can try something like this:
ActiveAdmin.register User do
form do |f|
f.inputs "User" do
f.input :name
end
f.inputs "Billing Profile" do
f.has_one :billing_profile do |bp|
w.input :address if can? :edit_billing_profile, bp.user
end
end
f.buttons
end
end
I have not test it, but I did something similar on a project.
This may help you-
Adding custom links:
ActiveAdmin.register User, :name_space => :example_namespace do
controller do
private
def current_menu
item = ActiveAdmin::MenuItem.new :label => "Link Name", :url => 'http://google.com'
ActiveAdmin.application.namespaces[:example_namespace].menu.add(item)
ActiveAdmin.application.namespaces[:example_namespace].menu
end
end
end
I basically created a new ActiveAdmin::MenuItem and add it to the current ActiveAdmin menu with the namespace example_namespace and return the menu in the end of the current_menu method. Note: current_menu is a method expected by ActiveAdmin so don't change the name of it. You can add as many items you like and each of these items will be converted to a link on your navigation header. Note this works for ActiveAdmin version > 0.4.3 so you might need to do your own digging if you want to do it for version <= 0.4.3.
I have a LinkHelper defined which has the following two methods:
#This will return an edit link for the specified object instance
def edit_path_for_object_instance(object_instance)
model_name = object_instance.class.to_s.underscore
path = send("edit_#{model_name}_path", object_instance)
end
#This will return an show link for the specified object instance
def show_path_for_object_instance(object_instance)
model_name = object_instance.class.to_s.underscore
path = send("#{model_name}_path", object_instance)
end
You can call the edit_path_for_object_instance method directly from your view and pass in the user.billing_profile object.
This will give you a link directly to the entity resulting a url like /billing_profile/ID/edit
An alternate approach is to use fields_for. This will allow you to create a form for the User attributes and update the associated BillingProfile at the same time. It would look something like this:
<%= form_for #user%>
<%= fields_for #user.billing_profile do |billing_profile_fields| %>
<%= billing_profile_fields.text_field :name %>
<% end %>
<%end%>
See here: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html

How do I access helpers I've written in Rails?

I've written a helper for my user model in user_helper.rb
module UserHelper
def get_array_of_names_and_user_ids
User.all(&:first_name) + User.all.map(&:user_id)
end
end
Unfortunately when I type in
<div class="field">
<%= f.label :assignee, "Assigned to" %>
<%= select(:task, :assignee_id, User.get_array_of_names_and_user_ids )%>
</div>
It can't see it. Where am I going wrong? I'm using devise.
You're close. The helper doesn't become a class method like that -- it becomes accessible as a method in your views. Just simply call get_array_of_names_and_user_ids.
Helpers are for views not for model.
For model you should define class methods in User model
class User
def self.get_array_of_names_and_user_ids
User.all(&:first_name) + User.all.map(&:user_id)
end
end
You don't need to hand code this helper as Rails provides a helper called collection_select for this purpose.
In your view simply add this:
<%= collection_select(:task, :assignee_id, User.all, :id, :first_name,
:prompt => true) %>
Note:
I am assuming you have a small set of users in your DB(<30). Otherwise, you have to use some other control to select users.
Helpers are methods that can be called in the view, not methods to be called on the model
Just call get_array_of_names_and_user_ids

Resources