Creating children objects of not saved model in Backbone using Backbone-relational - ruby-on-rails-3

I'm new to backbone. I have rails3 app. These are my backbone models:
class AppName.Models.Order extends Backbone.RelationalModel
paramRoot: 'order'
relations: [
type: Backbone.HasMany
key: 'order_services'
relatedModel: 'AppName.Models.OrderService'
collectionType: 'AppName.Collections.OrderServicesCollection'
includeInJSON: false
reverseRelation:
key: 'order_id',
includeInJSON: 'id'
]
class AppName.Models.OrderService extends Backbone.RelationalModel
paramRoot: 'order_service'
I have new order model which is not saved at server yet. How can I create new order_service as a child of that order, so I could access order with order_service.get('order')?
I need to build order step by step: add order_services, add other models, and then save the order. Is that possible to store locally not saved order with its order_services (which also have not saved children of other models) and then save all this stuff at server?

Related

How to use existing data from the database in Codeception FactoryMuffin?

I'm trying to set up easy test data in my Acceptance tests:
public function shouldUseAFakeAccountHolder(AcceptanceTester $I) {
$I->have(AccountHolder::class);
// ...
}
I've copied the example code from the Codeception documentation and modified it with my entity names (as well as fixing the bugs).
<?php
public function _beforeSuite()
{
$factory = $this->getModule('DataFactory');
// let us get EntityManager from Doctrine
$em = $this->getModule('Doctrine2')->_getEntityManager();
$factory->_define(AccountHolder::class, [
'firstName' => Faker::firstName(),
// Comment out one of the below 'accountRole' lines before running:
// get existing data from the database
'accountRole' => $em->getRepository(AccountRole::class)->find(1),
// create a new row in the database
'accountRole' => 'entity|' . AccountRole::class,
]);
}
The relationship using existing data 'accountRole' => $em->getRepository(AccountRole::class)->find(1) always fails:
[Doctrine\ORM\ORMInvalidArgumentException] A new entity was found through the relationship 'HMRX\CoreBundle\Entity\AccountHolder#accountRole' that was not configured to cascade persist operations for entity: HMRX\CoreBundle\Entity\AccountRole#0000000062481e3f000000009cd58cbd. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'HMRX\CoreBundle\Entity\AccountRole#__toString()' to get a clue.
If I tell it to create a new entry in the related table 'accountRole' => 'entity|' . AccountRole::class, it works, but then it adds rows to the table when it should be using an existing row. All the role types are known beforehand, and a new random role type makes no sense because there's nothing in the code it could match to. Creating a duplicate role works, but again it makes so sense to have a separate role type for each user since roles should be shared by users.
I've had this error before in Unit tests, not Acceptance tests, when not using Faker / FactoryMuffin, and it's been to do with accessing each entity of the relationship with a different instance of EntityManager. As soon as I got both parts using the same instance, it worked. I don't see how to override the native behaviour here though.
It works (at least in Codeception 4.x) by using a callback for the existing relation:
<?php
public function _beforeSuite()
{
$factory = $this->getModule('DataFactory');
$em = $this->getModule('Doctrine2')->_getEntityManager();
$factory->_define(AccountHolder::class, [
'firstName' => Faker::firstName(),
'accountRole' => function($entity) use ($em) {
$em->getReference(AccountRole::class)->find(1);
},
]);
}
I've found it here: https://github.com/Codeception/Codeception/issues/5134#issuecomment-417453633

Save DataObject relation when fields are added via getCMSFields()?

With this code the DataObject ID (InternalExternalLinkID) is not saved to the page when the CMS page is published, how to I automatically add the scaffolding from the dataobject and have the relationship saved (without manually doing onAfterWrite() as described at http://www.silverstripe.org/data-model-questions/show/11044):
class Page extends SiteTree {
private static $has_one = array(
'InternalExternalLink' => 'InternalExternalLink'
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldsToTab('Root.Main', singleton('InternalExternalLink')->getCMSFields());
I understand you probably need to create the dataobject first, get the ID and then save to the Page object - can the CMS not do this scaffolding, create (or update) and save this related dataobject automatically like ModelAdmin does?
You should use a GridField for this which handles saving to the nested object. Checkout the relational handler module for a has_one relationship editor. You can also get it working without the module if you don't want to install another dependancy. Just create a new GridField instance and pass your has_one record as an DataList query.
http://addons.silverstripe.org/add-ons/simonwelsh/gridfieldrelationhandler

How to use Model in diffrent controller with ROR

I am new new ROR and i am using ruby 1.9.3 and rails 3 version
I want to use Model in different controller.
For ex: My Controller name PackagesController and I want use OrderHistory Model in PackagesController.
See below code
class PackagesController < ApplicationController
def paypal
#data = params
#User.create(:name => "user1",:address=>"address1")
#package_id = #data[:pid]
#package_price = #data[:pprice]
OrderHistory.create(:admin_user_id => "1", :package_id=>package_id, :price=>package_price, :payment_status=>'pending' )
end
end
This code very time given error uninitialized constant PackagesController::OrderHistory
Please help
You can use any model in any controller. The problem elsewhere
Make sure that you have model class named OrderHistory saved in the file named order_history.rb

Create a form example in Yii

I've been struggling with creating a simple form that will later store data in the database, using Yii framework and none of the tutorials I have been following have been explanatory enough. The idea is that I am editing an existing Yii project and I need to add user registration functionality to the following project. So Gii is out of the option.
To my understanding I have created:
User controller (controllers/UserController.php)
User model (models/User.php)
Register view (/views/register.php)
What is the general idea that I should follow in order to create a form in the view, and add data from that form on the database?
On the controller so far I have:
class UserController extends LSYii_Controller {
public function actionIndex() { }}
The model:
public static function insertUser($new_user, $new_pass,$new_full_name,$parent_user,$new_email)
{
$oUser = new self;
$oUser->users_name = $new_user;
$oUser->password = hash('sha256', $new_pass);
$oUser->full_name = $new_full_name;
$oUser->parent_id = $parent_user;
$oUser->lang = 'auto';
$oUser->email = $new_email;
if ($oUser->save())
{
return $oUser->uid;
}
else{
return false;
}
}
and on the view I have nothing since I am not sure on how to proceed.
Any help will be greatly appreciated.
One of the nice things about Yii is it's plugin architecture. There is a user registration and management module that will do all of this for you. It's free and available from:
http://yii-user.2mx.org/
Features:
Login from User Name or Email
Registration
Activation accounts (verification email)
Recovery password (send recovery key to user email)
User profile page
Manage Users
Manage Profile Fields
Profile field widget for view, edit and save data (FieldWidget)
Date widget (jQueryUI datepicker)
File upload widget
Profile Relation Widget
API
You can edit the User class to add other fields or store those additional fields in another table if you didn't want to mess with the yii-user code/configuration.

Yii form and model for key-value table

I have a table which has only two column key-value. I want to create a form which allow user insert 3 pair of key-value settings.
Do I need pass 3 different models to the view? Or is there any possible way to do this?
Check out this link:
http://www.yiiframework.com/doc/guide/1.1/en/form.table
This is considered best form in Yii for updating for creating multiple models.
In essence, for creation you can create a for loop generate as many inputs a you wish to have visible, and in your controller loop over the inputs to create new models.
View File:
for ( $settings as $i=>$setting ) //Settings would be an array of Models (new or otherwise)
{
echo CHtml::activeLabelEx($setting, "[$i]key");
echo CHtml::activeLabelEx($setting, "[$i]key");
echo CHtml::error($setting, "[$i]key");
echo CHtml::activeTextField($setting, "[$i]value");
echo CHtml::activeTextField($setting, "[$i]value");
echo CHtml::error($setting, "[$i]value");
}
Controller actionCreate:
$settings = array(new Setting, new Setting, new Setting);
if ( isset( $_POST['Settings'] ) )
foreach ( $settings as $i=>$setting )
if ( isset( $_POST['Setttings'][$i] ) )
{
$setting->attributes = $_POST['Settings'][$i];
$setting->save();
}
//Render View
To update existing models you can use the same method but instead of creating new models you can load models based on the keys in the $_POST['Settings'] array.
To answer your question about passing 3 models to the view, it can be done without passing them, but to validate data and have the correct error messages sent to the view you should pass the three models placed in the array to the view in the array.
Note: The example above should work as is, but does not provide any verification that the models are valid or that they saved correctly
I'm going to give you a heads up and let you know you could potentially make your life very complicated with this.
I'm currently using an EAV patterned table similar to this key-value and here's a list of things you may find difficult or impossible:
use CDbCriteria mergeWith() to filter related elements on "value"s in the event of a search() (or other)
Filtering CGridView or CListView
If this is just very straight forward key-value with no related entity aspect ( which I'm guessing it is since it looks like settings) then one way of doing it would be:
create a normal "Setting" CActiveRecord for your settings table (you will use this to save entries to your settings table)
create a Form model by extending CFormModel and use this as the $model in your form.
Add a save() method to your Form model that would individually insert key-value pairs using the "Setting" model. Preferably using a transaction incase a key-value pair doesn't pass Settings->validate() (if applicable)
optionally you may want to override the Form model's getAttributes() to return db data in the event of a user wanting to edit an entry.
I hope that was clear enough.
Let me give you some basic code setup. Please note that I have not tested this. It should give you a rough idea though.:
Setting Model:
class Setting extends CActiveRecord
{
public function tableName()
{
return 'settings';
}
}
SettingsForm Model:
class SettingsForm extends CFormModel
{
/**
* Load attributes from DB
*/
public function loadAttributes()
{
$settings = Setting::model()->findAll();
$this->setAttributes(CHtml::listData($settings,'key','value'));
}
/*
* Save to database
*/
public function save()
{
foreach($this->attributes as $key => $value)
{
$setting = Setting::model()->find(array('condition'=>'key = :key',
'params'=>array(':key'=>$key)));
if($setting==null)
{
$setting = new Setting;
$setting->key = $key;
}
$setting->value = $value;
if(!$setting->save(false))
return false;
}
return true;
}
}
Controller:
public function actionSettingsForm()
{
$model = new Setting;
$model->loadAttributes();
if(isset($_POST['SettingsForm']))
{
$model->attributes = $_POST['SettingsForm'];
if($model->validate() && $model->save())
{
//success code here, with redirect etc..
}
}
$this->render('form',array('model'=>$model));
}
form view :
$form=$this->beginWidget('CActiveForm', array(
'id'=>'SettingsForm'));
//all your form element here + submit
//(you could loop on model attributes but lets set it up static for now)
//ex:
echo $form->textField($model,'fieldName'); //fieldName = db key
$this->endWidget($form);
If you want further clarification on a point (code etc.) let me know.
PS: for posterity, if other people are wondering about this and EAV they can check the EAV behavior extention or choose a more appropriate DB system such as MongoDb (there are a few extentions out there) or HyperDex