I am working in a Symfony 1.4 project with Propel 1.4.2.
I have 2 related tables. workshop and trainers which is a many to many relation mapped by a join table (workshop_trainers) which contains the workshop_id and the trainer_id).
In my Workshop Form I have a select box for adding the trainers to the workshop. The problem is when the workshop is new (Create) I get an error:
Cannot add or update a child row: a foreign key constraint fails
This happens because, when saving the workshop_trainers relation the workshop_id field is null. IsnĀ“t Propel intelligent enough to know that there is a relation between the tables and save the base object first? What I am doing wrong?
My trainer list widget.
$this->widgetSchema['workshop_trainer_list'] = new sfWidgetFormChoice(array(
'choices' => $trainers,
'multiple' => true,
));
Thanks for your help.
This is not fixing the problem but that's the easiest practical solution to this problem:
In the form, simply deactivate the workshop_trainer_list field if the object is a new one (doesn't have an ID yet).
Something like:
if ($this->getObject()->isNew())
{
$this->offsetUnset('workshop_trainer_list'); // not sure of that method name
}
A better solution is to update the doSave method to have the ID first, something like this:
protected function doSave($con = null)
{
$isNew = $this->getObject()->isNew();
if (null === $con)
{
$con = $this->getConnection();
}
// retrieve the value of workshop_trainer_list here and remove it from the form
$trainers = ...
$this->offsetUnset('workshop_trainer_list');
// save without it
parent::doSave($con);
// add it back
$this->getObject()->set...
// save
$this->getObject()->save($con);
}
Related
I have a model A which has an one2mny relation with another model B and the later has also an one2many relation with a model C.
I want to use self.update to update the one2many relation in the model A in and onchange method so accordingly update the one2many relation in the model B.
I have managed to update the first one but the second one is not updated here what i have done :
temp.append((0,0,{
'periode':periode,
'ca':ca,
'loc':loc,
'line_rs':line_rsc,
}))
self.update({
'periode_line':temp
})
where line_rsc is a list that should be used to update the second
one2many relation
Thanks
secod pic (secod one2many relation):
i tried this using the new api and it seems to be working just fine:
# this will add the new record to existing records
#api.onchange(..)
def .....(self):
self.update(
{'o2m_1_field': [{
'o2m_1_field_name': 'value',
'o2m_1_field_o2m_2_name': [{'o2m_2_field': 'value'}]
}]
}
)
this logic works fine in new api.
or you can do it like this
# this will add the new record to existing records
self.o2m_1_field += self.env['o2m.1.model.name'].new({
'o2m_1_field_name': 'value',
'o2m_1_field_o2m_2_name': [{'o2m_2_field': 'value'}]
})
if this is not working for you and giving you bad query error then you need to
use the latest version of odoo 8 because a lot has been changing you can even
do onchange on a o2m_field now ...
When a user updates an invoice form, i want to create a new invoice record with the updated attributes, but also change one or two fields of the old record and save it, too.
How would the outline of a controller action look like which could accomplish this?
Instead of a controller action i put the code in the model, using callbacks:
before_save do |rec|
if !rec.new_record?
attrb = rec.attributes.delete_if{|k, v| ["id"].include? k }
Book.create(attrb)
rec.restore_attributes
rec.year = rec.year + 2 # some custom change
true
end
end
I keep all attributes unless the 'id' (otherwise i get an error) for create a new record with the new attributes.
Then i restore the attributes of the existing record. I do some custom change before saving.
I am rather new with Rails but this seems pretty straightforward. As you mention the user is 'updating" an invoice, your controller view has probably been passed all the data available to the user for further change.
When submitting the form, your update action can easily update the current record data, as well as creating a new one on top of this
Though as it is automated, you need to make clear:
if a new invoice record is created each time an invoice record is
updated (thi can create a lot of copies of the same invoice)
how you make the old record an archive to avoid duplicates
can the 'additional" amendments be automated and easily processed through an algorithm...
Nested attributes made things a bit tricky. So in order to create new instances I had to use the dup method for both the resource and its nested items.
Generally, it is advisable to keep the controllers slim and make the models fat. Nevertheless, I have decided to include this code into my Invoices controller:
def revise_save
#contact = Contact.find(params[:contact_id])
#invoice = #contact.invoices.find(params[:invoice_id])
#invoice_old = #invoice.dup
#invoice.invoice_items.each do |item|
#invoice_old.invoice_items << item.dup
end
#invoice.datum = DateTime.now.to_date
# archive old invoice
# #invoice_old. ...
#invoice_old.save
# make old new invoice
#invoice.datum = Time.now
# ...
#invoice.update(invoice_params)
redirect_to invoices_path
end
Note that in this solution the currently edited (original) invoice becomes the new invoice, the old one is paradoxically created anew.
Thanks to #iwan-b for pointing me in the right direction.
I am facing trouble using doctrine join. I can't share my code. But I can tell you scenario.
Please help me to achieve that.
I have created 2 entity. One User and Language.
User table is having foreign key language_id. and Language is master table with id and code fields.
I want to fetch user with some criteria, such a way it returns Language code from Language table as well.
I write join for that but it returns some full object...
Not sure how to fetch corresponding language code from Language table for language_id set in user table
If there is some example you know which can help me then also fine
i have return this in __construct()
$this->languageObj = new ArrayCollection();
when we print it is gives this
[languageObj:User:private] => Common\User\Entity\Language Object
(
[languageId:Language:private] => 1
[languageCode:Language:private] => en
[languageName:Language:private] => English
[languageCode2:Language:private] => User Object
RECURSION
)
I am not able to fetch languageCode from the object
You need methods defined in your entity to return the value from the object. It seems like everything is correct you would just need to grab the value from the entity. Here is an example:
$userEntity->getLanguageObj()->getLanguageId();
Your user Entity would need the getLanguageObj method which you can define like this:
public function getLanguageObj() {
return $this->languageObj;
}
And your Language Entity would also need a getLanguageId method:
public function getLanguageId() {
return $this->languageId;
}
Hope that helps!
This is my first application using backbone and REST API, I'm a bit confused with some specific scenarios when it comes to creating-editing. So if the model exits on server, it will EDIT, if it doesn't it CREATES.
When I pass on a unique identifier in my model, it knows it exits, but if I pass a combination of existing data without a unique identifier it always assumes it should CREATE. I'm not sure if this should be solved on client side or server.
For instance:
var exportationMod = new Backbone.Model({ 'asset': '/api/v1/asset/'+this.assetID+'/', 'export_configuration': '/api/v1/exportconfiguration/'+this.model.get('id')+'/' });
exportationMod.url = '/api/v1/exportation/';
exportationMod.save();
OK so the server is running with django + tastypie. Should this be validated by the client by first making an extra query, on the server (maybe there is a way of setting a combination of unique keys like mysql), or is there another setting I can tweak so it edits instead of creating?
If you pass data to the server without some unique id, how would the server know what to update?
If it makes sense for your situation, you can override isNew() in your model.
var MyModel = Backbone.Model.extend({
idAttribute: 'somethingUnique',
url: '/api/v1/exportation/',
isNew: function(){
// return true if you want create (POST),
// return false if you want update (PUT)
}
});
By default it looks like this (with the above model, this.id would be the idAttribute value above):
// A model is new if it has never been saved to the server, and lacks an id.
isNew: function() {
return this.id == null;
},
If you want to edit something that already exists on the server, you should just fetch it first before editing/saving it. Also, if there is some unique id that is not called 'id' you can override that on the model as well (see above).
I'm trying to get a better setup working for updating a model with nested properties.
Right now in my edit view I define the textFieldTag manually to create the params struct by setting up the name as "myModel[myNestedProperty][#modelID#,#key2id#][name]"
in update action...
if I just use myModel.update(params.myModel) I can't get the update to work if there are any elements that require deletion
so I destroy all the models of the nested property that have the same id as myModel, in which case it works.
The downside is that if the update fails, the nested properties are all gone.
I've tried grabbing all of the models first before deleting them and .saveing them, but for some reason that's not working.
Looks like cfwheel is setup for this kind of relation with the checkboxes, but I need it to work with textfield and select items in my form.
Update
I realized I have another issue. Essentially I would like to expand on this to be able to use it across multiple nested properties and relationships.
the issue is in the way I setup the name especially for select dropdowns:
name="myModel[myNestedProperty][#modelID#, ][nestedID]"
the issue is that the second id cannot be declared, because it will be assigned as the id rather than using the value that I select.
To be honest, this is the one issue I've been battling with my whole time. I'm dealing with it by regenerating the models in the controller, I just forgot I haven't solved that issue yet.
Is there a way I can have these values not be used at all, and have them populated from the structure dynamically?
let's say I have (truncated) a name tcat[34,0][catID] or tcat[34,][catID], (where the catID should be the 2nd ID).
the params' tcat structure that gets generated is
[34,0]{catID = 12,14,18}
or
[34,]{catID = 12,14,18}
I'd like the params' tcat structure to have multiple structs like:
[34,12]{tID = 34; catID = 12}
[34,14]{tID = 34; catID = 14}
[34,18]{tID = 34; catID = 18}
Is there a way around this?
I'm working with a lot of composite key nested properties, and if I could have this part alone working it would make it a lot easier. I know one way is to update the name with javascript, but I think that would be the (very,very) last resort.
Can you give this a try?
Set up a callback in the parent model that checks to see if name is blank and flags for deletion if it's blank.
<cffunction name="init">
...
<!--- This could also be `beforeValidation` if you want to make `name` required for the child model --->
<cfset beforeSave("$provisionMyNestedProperty")>
</cffunction>
<cffunction name="$provisionMyNestedProperty">
<cfscript>
if (StructKeyExists(this, "myNestedProperty") && IsArray(this.myNestedProperty))
{
for (local.i = 1; local.i <= ArrayLen(this.myNestedProperty); local.i++)
{
if (!StructKeyExists(this.myNestedProperty[local.i], "name") || !Len(Trim(this.myNestedProperty[local.i].name)))
this.myNestedProperty[local.i]._delete = true;
}
}
</cfscript>
</cffunction>
I'll keep editing my answer until we can bang out a solution. Hopefully that gives you a good start though.