Please check your agent type and version and read on or switch to the right documentation.
Smart Fields
What is a Smart Field?
A field that displays a computed value in your collection.
A Smart Field is a column that displays processed-on-the-fly data. It can be as simple as concatenating attributes to make them human friendly, or more complex (e.g. total of orders).
Creating a Smart Field
On our Live Demo, the very simple Smart Field fullname is available on the customers collection.
Very often, the business logic behind the Smart Field is more complex and must be asynchronous. To do that, please have a look at this section.
On our Live Demo, the very simple Smart Field fullname is available on the Customer collection.
/lib/forest_liana/collections/customer.rb
classForest::CustomerincludeForestLiana::Collection collection :Customer field :fullname, type: 'String'do"#{object.firstname}#{object.lastname}"endend
Very often, the business logic behind the Smart Field is more complex and must interact with the database. Here’s an example with the Smart Field full_address on the Customer collection.
/lib/forest_liana/collections/customer.rb
classForest::CustomerincludeForestLiana::Collection collection :Customer field :full_address, type: 'String'do address =Address.find_by(customer_id: object.id)"#{address[:address_line_1]}#{address[:address_line_2]}#{address[:address_city]}#{address[:country]}"endend
On our Live Demo, the very simple Smart Field fullname is available on the Customer collection.
Ensure the file app/forest/__init__.py exists and contains the import of the previous defined class :
app/forest/__init__.py
from app.forest.customer import CustomerForest
Very often, the business logic behind the Smart Field is more complex and must interact with the database. Here’s an example with the Smart Field full_address on the Customer collection.
Very often, the business logic behind the Smart Field is more complex and must interact with the database. Here’s an example with the Smart Field full_address on the Customer model.
The collection name must be the same as the model name.
Updating a Smart Field
By default, your Smart Field is considered as read-only. If you want to update a Smart Field, you just need to write the logic to “unzip” the data. Note that the set method should always return the object it’s working on. In the example hereunder, the customer object is returned including only the modified data.
For security reasons, the fullname Smart field will remain read-only, even after you implement the set method. To edit it, disable read-only mode in the field settings.
By default, your Smart Field is considered as read-only. If you want to update a Smart Field, you just need to write the logic to “unzip” the data. Note that the set method should always return the object it’s working on. In the example hereunder, the customer record is returned.
For security reasons, the fullname Smart field will remain read-only, even after you implement the set method. To edit it, disable read-only mode in the field settings.
By default, your Smart Field is considered as read-only. If you want to update a Smart Field, you just need to write the logic to “unzip” the data. Note that the set method should always return the object it’s working on. In the example hereunder, the user_params is returned is returned including only the modified data.
/lib/forest_liana/collections/customer.rb
classForest::CustomerincludeForestLiana::Collection collection :Customer set_fullname =lambdado|user_params, fullname| fullname = fullname.split user_params[:firstname] = fullname.first user_params[:lastname] = fullname.last# Returns a hash of the updated values you want to persist. user_paramsend field :fullname, type: 'String', set: set_fullname do"#{object.firstname}#{object.lastname}"endend
For security reasons, the fullname Smart field will remain read-only, even after you implement the set method. To edit it, disable read-only mode in the field settings.
By default, your Smart Field is considered as read-only. If you want to update a Smart Field, you just need to write the logic to “unzip” the data. Note that the set method should always return the object it’s working on. In the example hereunder, the customer object is returned including only the modified data.
To perform a search on a Smart Field, you also need to write the logic to “unzip” the data, then the search query which is specific to your zipping. In the example hereunder, the firstname and lastname are searched separately after having been unzipped.
classForest::CustomerincludeForestLiana::Collection collection :Customer search_fullname =lambdado|query, search| firstname, lastname = search.split# Injects your new filter into the WHERE clause. query.where_clause.send(:predicates)[0] <<" OR (firstname = '#{firstname}' AND lastname = '#{lastname}')" queryend field :fullname, type: 'String', set: set_fullname, search: search_fullname do"#{object.firstname}#{object.lastname}"endend
classForest::CustomerincludeForestLiana::Collection collection :Customer filter_fullname =lambdado|condition, where| first_word = condition['value'] && condition['value'].split[0] second_word = condition['value'] && condition['value'].split[1]case condition['operator']when'equal'"firstname = '#{first_word}' AND lastname = '#{second_word}'"when'ends_with'if second_word.nil?"lastname LIKE '%#{first_word}'"else"firstname LIKE '%#{first_word}' AND lastname = '#{second_word}'"end# ... And so on with the other operators not_equal, starts_with, etc.endend field :fullname, type: 'String', is_read_only: false, is_required: true, is_filterable: true, filter: filter_fullname do
"#{object.firstname}#{object.lastname}"endend
<?phpnamespaceApp\Models;useForestAdmin\LaravelForestAdmin\Services\Concerns\ForestCollection;useForestAdmin\LaravelForestAdmin\Services\SmartFeatures\SmartAction;useForestAdmin\LaravelForestAdmin\Services\SmartFeatures\SmartField;useIlluminate\Database\Eloquent\Builder;useIlluminate\Database\Eloquent\Factories\HasFactory;useIlluminate\Database\Eloquent\Model;useIlluminate\Database\Eloquent\Relations\HasMany;/** * Class Customer */classCustomerextendsModel{useHasFactory,ForestCollection;/** * @returnSmartField */publicfunctionfullname():SmartField {return$this->smartField(['type'=>'String'])->get(fn() => $this->firstname .' '.$this->lastname)->set(function ($value) { [$firstname, $lastname] =explode(' ', $value);$this->firstname = $firstname;$this->lastname = $lastname;return$this; })->filter(function (Builder $query, $value,string $operator,string $aggregator) { $data =explode(' ', $value);switch ($operator) {case'equal': $query->where(fn($query) => $query->where('firstname', $data[0])->where('lastname', $data[1]),null,null, $aggregator);break;case'ends_with':if ($data[1] ===null) { $query->where(fn($query) => $query->whereRaw("lastname LIKE ?", ['%'. $data[0] .'%']),null,null, $aggregator); } else { $query->where(fn($query) => $query->whereRaw("firstname LIKE ?", ['%'. $value .'%'])->whereRaw("lastname LIKE ?", ['%'. $value .'%']),null,null, $aggregator); }break;//... And so on with the other operators not_equal, starts_with, etc.default:thrownewForestException("Unsupported operator: $operator" ); }return $query; }); }}
Make sure you set the option isFilterable: true in the field definition of your code. Then, you will be able to toggle the "Filtering enabled" option in the browser, in your Fields Settings.
Sorting
Sorting on a Smart Field is not natively supported in Forest Admin. However you can check out those guides:
To optimize your smart field performance, we recommend using a mechanism of batching and caching data requests.
Implement them using the DataLoader which is a generic utility to be used as part of your application's data fetching layer to provide a simplified and consistent API over various remote data sources.