Why input fields based on ActiveForm are ignoring model attributes' default values?

I have the following validation rule to set default value for my model:

['from', 'default', 'value' => 2],

It works like a charm when dealing with this model in RESTful application. I.e. if PUT or POST requests are not providing this value, it is automatically set to given default value.

But, when I use it in MVC application:

<?= $form->field($model, 'from')->dropdownList($devices); ?>

Then this is clearly ignored. When displaying given form in “update” view then of course this works:

<select id="command-from" class="form-control" name="Command[from]">
<option value="1">The Server</option>
<option value="2" selected="">The Platform</option>
</select>

But when used in “create” view the default value of model’s attribute no such thing happens:

<select id="command-from" class="form-control" name="Command[from]">
<option value="1">The Server</option>
<option value="2">The Platform</option>
</select>

How to achieve some similarity here? So dropdown list is always set to some value:

  • actual model attribute’s value in “update” view,
  • model attribute’s default value in “create” view.

And, as always, to feed my curiosity – why this is not happening out-of-the-box? Or what am I missing?

Rules you declare are for validating when model is being loaded with values after the form is submitted. When you prepare data for ‘create’ view you are create new, empty instance. So you have to load attributes value implicitely by calling https://www.yiiframework.com/doc/api/2.0/yii-db-activerecord#loadDefaultValues()-detail (if you did set them in database schema - migrations) or explicitely for example in object constructor or in the controller. Another option is to define scenario in your model applying only ‘default’ rules in it and then calling ‘validate’ method on object.

2 Likes

I know this method. For some reason I was assuming that it loads default values from both DB schema and from model’s validation rules.

BTW: When using controllers generated by Yii, call to this method is already added:

if ($this->request->isPost) {
    if ($model->load($this->request->post()) && $model->save()) {
        return $this->redirect(['view', 'id' => $model->id]);
    }
} else {
    $model->loadDefaultValues();
}

I’m not aware of this method. Can you share some example or point me to a correct part of the guide?

There is no default() method of yii\db\Migration so I can’t call:

'name' => $this->string(15)->default('John'),
'surname' => $this->string(25)->default('Smith'),

Right?

If I do so, if I separate all the default-like rules to some special scenario, will it be automatically triggered by Yii during create and update? Or by adding scenario to some attribute I am explicitly saying that Yii should not trigger this rule automatically and I must manually trigger it during each $model->save()?

Here you are:
https://www.yiiframework.com/doc/guide/2.0/en/db-migrations#foreign-keys
'category_id' => $this->integer()->defaultValue(1),
https://www.yiiframework.com/doc/api/2.0/yii-db-columnschemabuilder#defaultValue()-detail

No.

Not in any other scenarios except those you defined.

No. You can try to define rule being applied in your and also in the default scenario:
https://www.yiiframework.com/doc/api/2.0/yii-base-model#rules()-detail

'on' => ['{scenarioWithDefaults}', 'yii\base\Model::SCENARIO_DEFAULT'],
2 Likes