Laravel 5.1 Mass Assignment Fillable Properties Being Ignored on Update? - laravel-5.1

I have the following models:
class User {
public function recruiter()
{
return $this->hasOne('App\Recruiter');
}
}
class Recruiter extends Model {
public function jobs()
{
return $this->hasMany('App\Job');
}
}
class Job extends Model {
protected $fillable = [
'job_type_id',
'recruiter_id',
'start_at',
'end_at',
'job_title',
'job_ref',
'job_desc'
];
// other stuff
}
When I call the following create method the fillable properties on the Job model work as expected.
$job = Auth::user()->recruiter->jobs()->create($request->all());
When I call the update method the fillable properties are ignored and end up with mass assignment vulnerability.
Auth::user()->recruiter->jobs()->update($request->all());
Why is this happening?

It's because you need to pass the id of the job as well (Laravel dosen't know what to update). So added to the fillable array.
class Job extends Model {
protected $fillable = [
'id',
'job_type_id',
'recruiter_id',
'start_at',
'end_at',
'job_title',
'job_ref',
'job_desc'
];
// other stuff
}

It seems like there is a weird bug. With this, still in Laravel 5.7.
You need to do this, for it to respect $fillable:
$jobs = Auth::user()->recruiter->jobs();
$jobs->update($request->all());
Don't ask me why, but if you try:
(Auth::user()->recruiter->jobs())->update($request->all());
It just ignores $fillable.

Related

Grails data binding field exclusion

I am using Grails 2.5 and use Grails databinding in request methods.
For a basic example of the situation consider the following:
Domain class
class Product {
String field1
String privateField
}
Controller
class ProductController {
def update(Product productInstance) {
productInstance.save()
}
}
If I pass an existing Product to the controller like
{"id":3, "privateField":"newValue","field1":"whatever"}
the old value of privateField is overwritten. I want to enforce, that privateField is never bound from a request and avoid checking if the field is dirty.
Is there a mechanism in Grails to achieve this?
If I have to do the dirty check, how can I discard the new value and use the old one?
Pretty sure there's a "bindable" constraint.
http://grails.github.io/grails-doc/2.5.x/ref/Constraints/bindable.html
class Product {
String field1
String privateField
static constraints = {
privateField bindable: false
}
}
Should keep that field from binding automatically.
You can enforce which values are bound, but you'll need to change your method signature to get more control of the data binding process.
class ProductController {
def update() {
def productInstance = Product.get(params.id)
bindData(productInstance, params, [exclude: ['privateField']]
productInstance.save()
}
}

How to detect which field has been updated in afterUpdate|beforeUpdate GORM methods

i use afterUpdate method reflected by GORM API in grails project.
class Transaction{
Person receiver;
Person sender;
}
i want to know which field modified to make afterUpdate behaves accordingly :
class Transaction{
//...............
def afterUpdate(){
if(/*Receiver is changed*/){
new TransactionHistory(proKey:'receiver',propName:this.receiver).save();
}
else
{
new TransactionHistory(proKey:'sender',propName:this.sender).save();
}
}
}
I can use beforeUpdate: and catch up the object before updating in global variable (previous as Transaction), then in afterUpdate, compare previous with the current object.
Could be?
Typically this would be done by using the isDirty method on your domain instance. For example:
// returns true if the instance value of firstName
// does not match the persisted value int he database.
person.isDirty('firstName')
However, in your case if you are using afterUpdate() the value has already been persisted to the database and isDirty won't ever return true.
You will have to implement your own checks using beforeUpdate. This could be setting a transient value that you later read. For example:
class Person {
String firstName
boolean firstNameChanged = false
static transients = ['firstNameChanged']
..
def beforeUpdate() {
firstNameChanged = this.isDirty('firstName')
}
..
def afterUpdate() {
if (firstNameChanged)
...
}
...
}

Grails - List of Long not getting saved

I have a domain class similar to the following:
class Record {
Long id
List numbers = []
String description
void recordNumber(Long number) {
//requirements, validations, etc.
numbers << number
}
}
Then I defined a Web service similar to the code below:
class RecordController extends RestfulController {
def recordNumber(Record record) {
def number = getNumberFromRequest() //request.JSON, request.XML, etc.
if (record) {
record.recordNumber(number)
record.save(flush: true, failOnError: true)
}
}
}
However, the numbers on the list don't seem to get saved, because when I retrieve a Record, the list empty. I have test for the code and it seems ok. Could it also be that the list is lazily loaded?
You are saving a new record instance each time the action is called. You should load it out of the DB instead:
def recordNumber( Long id ){
def record = Record.get id
def number = getNumberFromRequest() //request.JSON, request.XML, etc.
//....
}
So based on this answer from a previous StackOverflow question, I updated the code as follows:
class Record {
static hasMany = [numbers: Long]
Long id
String description
void recordNumber(Long number) {
//requirements, validations, etc.
addToNumbers number
}
}
It would seem that if a collection is meant to be persistent, it has to be declared this way, or be mapped in some other methods; I'm just not sure what those other methods are.

Service access in beforeDelete()

I want to call a service inside my grails domain objects beforeDelete() event. Unfortunately it always crashes reproducibly when the event is fired. I built an example that reproduces the problem. The domain object:
class Gallery {
def myService
def beforeDelete() {
// System.out.println(myService); // not even this works, same error!
System.out.println(myService.say());
}
}
The service:
class MyService {
String say() {
"hello"
}
}
The test controller:
class DeleteController {
def index() {
Gallery.list().each {
it.delete()
}
}
def create() {
def gallery = new Gallery()
gallery.save()
}
}
If I start the application and call create followed by index I get:
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [testbeforedelete.Gallery#1]
What I want to accomplish is to call my service, which is a bit more complicated than this example. I cannot explain this behavior and I don't know how cope with this. I know that the Hibernate events need special care yet I'm stuck.
The beforeDelete actually makes a change to your domainclass. I agree that you would not expect this behaviour. Hibernate thinks that you are modifying the instance. You could use the follow code to get around your problem
def beforeDelete() {
Gallery.withNewSession {
System.out.println(myService.say());
}
}

custom Grails validation

Normally for a Grails domain or command class, you declare your constraints and the framework adds a validate() method that checks whether each of these constraints is valid for the current instance e.g.
class Adult {
String name
Integer age
void preValidate() {
// Implementation omitted
}
static constraints = {
name(blank: false)
age(min: 18)
}
}
def p = new Person(name: 'bob', age: 21)
p.validate()
In my case I want to make sure that preValidate is always executed before the class is validated. I could achieve this by adding a method
def customValidate() {
preValidate()
validate()
}
But then everyone who uses this class needs to remember to call customValidate instead of validate. I can't do this either
def validate() {
preValidate()
super.validate()
}
Because validate is not a method of the parent class (it's added by metaprogramming). Is there another way to achieve my goal?
You should be able to accomplish this by using your own version of validate on the metaclass, when your domain/command class has a preValidate() method. Something similar to the below code in your BootStrap.groovy could work for you:
class BootStrap {
def grailsApplication // Set via dependency injection
def init = { servletContext ->
for (artefactClass in grailsApplication.allArtefacts) {
def origValidate = artefactClass.metaClass.getMetaMethod('validate', [] as Class[])
if (!origValidate) {
continue
}
def preValidateMethod = artefactClass.metaClass.getMetaMethod('preValidate', [] as Class[])
if (!preValidateMethod) {
continue
}
artefactClass.metaClass.validate = {
preValidateMethod.invoke(delegate)
origValidate.invoke(delegate)
}
}
}
def destroy = {
}
}
You may be able to accomplish your goal using the beforeValidate() event. It's described in the 1.3.6 Release Notes.

Resources