I have a Rails app that uses activescaffold and I would like to hide some fields on the update for some of the records.
I have been trying to do it using helper methods, but I can not seem to get that to work.
What is the best way to do this?
I have a Rails app that uses activescaffold and I would like to hide some fields on the update for some of the records.
I have been trying to do it using helper methods, but I can not seem to get that to work.
What is the best way to do this?
The best way to do this is by using one of the security method templates (depending on your need) provided by activescaffold plugin.
Pasted from activescaffold wiki:
Model Methods: Restricting Anything Else
On your model object you may define methods (none of which accept any arguments) in any of four formats, depending on your need for granularity.
The formats are:
* #{column_name}_authorized_for_#{crud_type}?
For example if you have an activescaffold based controller called user:
class Admin::UsersController < ApplicationController
active_scaffold do |config|
config.columns = [:username, :name, :email]
end
end
And you only want to allow the user to be able to update the username if they are admin then you can do something like this:
User Model:
class User < ActiveRecord::Base
# ActiveScaffold security template: #{column_name}_authorized_for_#{crud_type}?
def username_authorized_for_update?
# As soon as this method will return false
# the username field will not be available on the update form
return true # Write logic to decide if username field should be visible
end
end
Active Scaffold wiki link: https://github.com/activescaffold/active_scaffold/wiki/Security
If you just want to hide some columns in the update view, then to configure this in the controller is quite easy.
Either you can specify the columns you want to see:
class DocumentsController < ApplicationController
active_scaffold :document do |config|
config.columns = [ :id, :product, :title, :document_type, :author, :organization, :document_approver, :document_location ]
config.list.columns = [ :id, :product, :title, :document_type, :author ]
config.show.columns = [ :product, :title, :document_type, :author, :organization, :document_approver, :document_location ]
config.create.columns = [ :product, :title, :document_type, :document_approver, :document_location ]
config.update.columns = [ :product, :title, :document_type, :organization, :document_approver, :document_location ]
end
end
Or you can exclude the ones you want to hide:
class DocumentsController < ApplicationController
active_scaffold :document do |config|
config.columns = [ :id, :product, :title, :document_type, :author, :organization, :document_approver, :document_location ]
config.list.columns.exclude :organization, :document_approver, :document_location
config.show.columns.exclude :id
config.create.columns.exclude :id, :author, :organization
config.update.columns.exclude :id, :author
end
end
Note that the 'config.columns' is used to define the total number of columns for the controller, and if any of 'list', 'show', 'create' or 'update' are not specifically defined, then 'config.columns' is used per default.
This also means, that if you want the same columns visible for all views except 'update', then you can just define it like:
class DocumentsController < ApplicationController
active_scaffold :document do |config|
config.columns = [ :id, :product, :title, :document_type, :author, :organization, :document_approver, :document_location ]
config.update.columns = [ :product, :title, :document_type, :organization, :document_approver, :document_location ]
end
end
Or:
class DocumentsController < ApplicationController
active_scaffold :document do |config|
config.columns = [ :id, :product, :title, :document_type, :author, :organization, :document_approver, :document_location ]
config.update.columns.exclude :id, :author
end
end
The security model methods as mentioned in other answers are a good option, however in my case I wanted to allow the field to be shown or hidden depending on the data entered into other columns, by chaining form fields. When using the security model methods, nothing at all is rendered for the field whose security method returned false, which prevents the ActiveScaffold update_column
javascript from re-rendering that field when the related column gets updated.
As a simplified example, if my WritingUtensilsController has
config.columns[:type].form_ui = :select
config.columns[:type].options = { options: %w( pencil pen crayon ) }
config.columns[:type].update_columns = [ :ink_color ]
config.columns[:type].send_form_on_update_column = true
And I want the ink_color field to only show up if the type dropdown is set to "pen", using the security method would not work here, because when the type dropdown is changed, we can't locate the ink_color column to update.
Override the form column partial for the ink_color column (_ink_color_form_column.erb) to conditionally render the normal field, OR a hidden input (with no name attribute but the correct class) inside a dl
tag depending on whether or not the writing utensil is a pen:
<% if record.is_pen? %>
<%= form_attribute(column, record, scope, false) %>
<% else %>
<dl><input type="hidden" class="<%= column.name %>-input"></dl>
<% end %>
Calling the form_attribute
method will cause the column to be rendered as normal. When the record is not a pen however, the hidden input will allow the javascript to target the parent dl
of the input with class ink_color-input
for replacement when the type column gets updated by the user.
add an after_render_field
method in your controller to manipulate your record when the update_column process happens:
def after_render_field(record, column)
if column.name == :type
if record.type == 'pen'
record.last_sharpened = nil
end
end
end
be sure to add last_sharpened to the update_columns array if you want it to be re-rendered with the new value as well
whizcreed's answer is correct, and these ActiveScaffold security model methods are in fact evaluated per-record, so you could do something like this in the model:
def username_authorized_for_update?
return true unless existing_record_check?
return false if userrights != 'admin'
return true
end
where userrights is a string field on this record (admittedly poor example) - but replace this conditional with whatever you want to check on that existing model object.