Ember.js find single item without ID - ruby-on-rails

I’m building an Ember.js application, using Ember data, ActiveModel serializer, and Ember Simple Auth Devise, connecting to a Rails API and trying to understand how I could build a route that loads a single resource, in this case for a "my account" page for the current user.
From the Rails perspective I don't need an ID, but on the Ember side I’m not sure how to accomplish this. My workaround has been to supply a placeholder ID, which Rails ignores. Is there a better way to accomplish this?
Ember.js:
MyAccountRoute = Ember.Route.extend(model: -> #store.find 'account', '1')
Rails:
def show
#item = #current_user.account
end

Ember Data has a very specific implementation when you use find
find called with the type only expects a collection of that type, this maps to findAll
find called with the type and a primitive type (non object) will expect a single object response of that type, this maps to findById
find called with the type and an object will expect a collection (possibly filtered server side by the parameters sent in), this maps to findByQuery
So using Ember Data there is no way to do this, unless you want to hack it into one of your other implementations, or use ajax to call back and then sideload the store. I prefer using the pattern you're using, I do this.store.find('user', 'me'); And then ignore the parameter.

The way I am tackling this is by returning an array/collection of records that only contains a single record.
Then in Ember you can access this single result using .get('firstObject') like this
export default Ember.Route.extend({
model: function() {
return this.store.find('user').then(function (users) {
return users.get('firstObject');
});
}
});
This feels more like an Ember way of doing things and also avoids an issue you may notice if you use the Ember developer tools plugin; That the returned data actually creates a duplicate record - you end up with an empty record with an id of me or 1 and a complete record with the ID of the single record returned.
An alternative approach is continue using me or 1 and to set or modify the ID of the returned record to match. In this case you would return a single object and not an array/collection.

Ember data has queryRecord method.
This method makes a request for one record, where the id is not known beforehand
http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord

I combined the two answers and used queryRecord with a parameter ignored by server.
return this.store.queryRecord('user_settings', {id: 'me'});
thanks Binarytales and antulik

Related

What is the difference between new sap.ui.model.odata.ODataModel and read?

I am playing around with a OData service and I am very confused when to use this
var oModel = new sap.ui.model.odata.ODataModel("proxy/http/services.odata.org/V3/(S(k42qhed3hw4zgjxfnhivnmes))/OData/OData.svc");
this.getView().setModel(oModel);
vs
var oModel = new sap.ui.model.odata.ODataModel("odatserviceurl", true);
var productsModel = new JSONModel();
oModel.read("/Products",
null,
null,
false,
function _OnSuccess(oData, response) {
var data = { "ProductCollection" : oData.results };
productsModel.setData(data);
},
function _OnError(error) {
console.log(error);
}
);
this.getView().setModel(productsModel);
I have two working example using both approach but I am not able to figure out why using read method if I can achieve same with first version. Please explain or guide me to the documentation which can clear my confusion.
Ok, lets start with the models:
JSON Model : The JSON model is a client-side model and, therefore, intended for small datasets, which are completely available on the client. The JSON model supports two-way binding. NOTE: no server side call is made on filtering, searching, refresh.
OData Model : The OData model is a server-side model: the dataset is only available on the server and the client only knows the currently visible rows and fields. This also means that sorting and filtering on the client is not possible. For this, the client has to send a request to the server. Meaning searching/filtering calls odata service again.
Now, lets look at scenarios where we will use these models:
Scenario 1: Showing data to user in a list/table/display form. Data manipulation is limited to searching and filtering. Here, I would use oData model directly to controls as only fetching of data is required.( your method 1) (NOTE: One way binding). Remember here all changes require a call to server.
Scenario 2: I have an application which has multiple inputs, user can edit changes, also some fields are calculated and mandatory. All in all, many user changes are done which may be temporary and user might not want to save them. Here, you dont want to send these temporary changes to backend as yet. You way want to manipulate, validate data before sending. Here, we will use JSON Model after reading data from odata model ( your method 2). Store the changes in local JSON model, validate and manipulate them and finally send the data using Odata create/update. Remember here all changes DO NOT require a call to server as data is present in local JSON MODEL.
Let me know if this helps you. :)
EDIT : Additional Information :
As per your comment :
Documentation says oModel.read' trigger get request but new sap.ui.model.odata.ODataModel("proxy/http/services.odata.org‌​/V3/(S(k42qhed3hw4zg‌​jxfnhivnmes))/OData/‌​OData.svc")` does the same thing so why and when to use oModel.read
Here, is where you misunderstood. The code
new sap.ui.model.odata.ODataModel("proxy/http/services.odata.org‌​/V3/(S(k42qhed3hw4zg‌​jxfnhivnmes))/OData/‌​OData.svc") will NOT send a read/get Request. It calls the odata services and fetches the metadata of the service. A service can have multiple entities.
For example: the service :http://services.odata.org/Northwind/Northwind.svc/ has mutiple entity sets such as Categories, Customers, Employees etc. So, when I declare : new sap.ui.model.odata.ODataModel("http://services.odata.org/Northwind/Northwind.svc/") it will fetch the metadata for service (not actual data). Only when you call the desired entity set, it will fetch the data. The Entity set is specified :
When you call the read method ( like you have specified '/Products')
Bind the entity set name directly to control like to List,Table etc ( items='{/Products}' )

Grails findById( null ) returning "random" result

I found a very strange behavior in our grails application today that i want to share with you.
We are using grails 2.3.11 on mysql 5.1.48.
We had a DomainObject.findById( id ) in one of your Controller actions.
We failed to check the id for a null value so DomainObject.findById( null )
would be called when no id is passed as an argument.
Normally DomainObject.findById( null )
will return null but there is a special condition that will yield other results!
If the controller action called before that inserted a new record in the database (lets call it Object B), regardless of the domain object stored, the DomainObject.findById( null ) will find the DomainObject with the same Id the Object B got on insert.
So when the controller action called before saved anything the findById(null) will return a row. And that row will have the same id the last inserted element got.
I am totally aware that using findById(null) is not the desired way to do it but I was quite shocked about the results it yielded. But returning any seemingly "random" result seems very strange to me.
I also want to note that DomainObject.get(null) will not suffer from this problem.
Anybody else witnessed this?
There is an active Jira pointing in this direction: https://jira.grails.org/browse/GRAILS-9628 but its not really describing this issue.
We don't really support passing null as an argument to a dynamic finder like that. Dynamic finders have explicit support for querying by null. Instead of DomainClass.findByName(null) you would call DomainClass.findByNameIsNull(). If you have a reference that may or may not be null, instead of passing that as an argument to a dynamic finder, the code can almost always be made cleaner by writing a criteria query or a "where" query that has a conditional in it.
I hope that helps.
Thx for your information scot.
I have further details. This behaviour is also altered by the underlying database.
While mysql suffers from this, maria-db (a mysql clone) does not!
So what happens is bound to the underlying database system.
That should not happen to an abstraction layer ....

Hydrating Database

I am new to learning and understanding how Hydration works, just wanted to point that out first. I'm currently able to Hydrate Select and Insert queries without any problems.
I am currently stuck on trying to Hydrate Update queries now. In my entity I have setup the get/set options for each type of column in my database. I've found that the ObjectProperty() Hydrator works best for my situation too.
However whenever I try to update only a set number of columns and extract via the hydrator I am getting errors because all the other options are not set and are returning null values. I do not need to update everything for a particular row, just a few columns.
For example in my DB Table I may have:
name
phone_number
email_address
But I only need to update the phone_number.
$entity_passport = $this->getEntityPassport();
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => '1'
));
This returns an error because setName() and setEmailAddress() are not included in this update and the query returns that the values cannot be null. But clearly when you look at the DB Table, there is data already there. The data that is there does not need to be changed either, only in this example does the PrimaryPhone() number.
I've been looking and reading documentation all over the place but I cannot find anything that would explain what I am doing wrong. I should note that I am only using Zend\Db (Not Doctrine).
I'm assuming I've missed something someplace due to my lack of knowledge with this new feature I'm trying to understand.
Perhaps you don't Hydrate Update queries... I'm sort of lost / confused. Any help would be appreciated. Thank you!
I think you're having a fundamental misconception of hydration. A hydrator simply populates an entity object from data (hydrate) and extracts data from an entity object (extract). So there are no separate hydrators for different types of queries.
In your update example you should first retrieve the complete entity object ($entity_passport) and then pass it to the TableGateway's update method. You would retrieve the entity by employeeid, since that's the condition you're using to update. So something like this:
$entity_passport = $passportMapper->findByEmployeeId(1);
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => $entity_passport->getId()
));
This is assuming you have some sort of mapper layer. Otherwise you could use your passport TableGateway (I assume that's what getTablePassport() returns, no?).
Otherwise, if you think retrieving the object is too much overhead and you just want to run the query you could use just a \Zend\Db\Sql\Sql object, ie:
$sql = new \Zend\Db\Sql\Sql($dbAdapter);
$update = $sql->update('passport')
->set(array('primary_phone' => $entity_passport->getPrimaryPhone()))
->where(array('employeeid' => $employeeId));
Edit:
Maybe it was a mistake to bring up the mapper, because it may cause more confusion. You could simply use your TableGateway to retrieve the entity object and then hydrate the returned row:
$rows = $this->getTablePassport()->select(array('employeeid' => 1));
$entity_passport = $this->getHydrator($rows->current());
[...]
Edit 2:
I checked your gist and I noticed a few things, so here we go:
I see that your getTablePassport indeed does return an object which is a subclass of TableGateway. You have already set up this class for it to use a HydratingResultset. This means you don't need to do any manual hydrating when retrieving objects using the gateway.
You also already implemented a Search method in that same class, so why not just use that? However I would change that method, because right now you're using LIKE for every single column. Not only is it very inefficient, but it will also give you wrong results, for example on the id column.
If you were to fix that method then you can simply call it in the Service object:
$this->getTablePassport->Search(array('employeeid' => 1));
Otherwise you could just implement a separate method in that tablegateway class, such as
public function findByEmployeeId($employeeId)
{
return $tableGateway->select(array('employeeid' => $employeeId));
}
This should already return an array of entities (or one in this specific case). P.S. make sure to debug and check what is actually being returned when you retrieve the entity. So print_r the entity you get back from the PassportTable before trying the update. You first have to make sure the retrieval code works well.

How do I filter out attributes that shouldn't be in a POST request in Backbone?

I have a Rails application with the backbone-rails gem. Which works out fine but Backbone tries to send a request with all the attributes of the model. Is there a way I can filter out some of the attributes that will be POST'd on an update/new? This would work great for those virtual attributes and attributes that can't be mass assigned.
There is no harm in posting attributes that cannot be mass assigned. You will see a warning, but everything will work.
There are basically two ways of actually removing unwanted attributes. The first is to customize the Model's toJSON(). For example:
myModel = Backbone.Model.extend({
function: toJSON() {
var json = _.clone(this.attributes);
delete json.somethingIdontWant
delete json.somethingElse
return json
}
})
The second, and less clean way, is to explicitly pass the data in your call to Model.save(). If you are using the default Backbone.sync() method, then this data will be used instead. For example:
mything.save({
data: {just: "the stuff", that: "i want to post"}
})
You can probably figure out a way to generalize either of those approaches, depending on which one works for you.

Where to store a Doctrine variable created in a component so that it's accessible anywhere?

Note I am referring to one request, and not several requests and sessions.
I have several components that require Doctrine user object, some are located in layout, others are located in templates. Sometimes I need that Doctrine user object in action. Currently I have added a function to sfUser class that loads that object from database, which means every time I call that function I make a call to db. I'd like to know where to store this object so that I can access it without having to query db every time I need it. Again, we're talking about a single request, not several requests or something that would require session.
Can I save it in sfContext somehow? Any other places so that it can be available everywhere?
You can store it in your model's Table class, because tables are always accessed as singletones.
class sfGuardUserTable extends PluginsfGuardUserTable
{
protected $specialUser = null;
public function getSpecialUser()
{
if (null === $this->specialUser)
{
$this->specialUser = $this->findOneById(1);
}
return $this->specialUser;
}
}
Now, you can use this in actions and components like this:
$u = sfGuardUserTable::getInstance()->getSpecialUser();
And you will always end up with one query.
you can configure Doctrine cache so that the result of this specific request is always cached. What if so good about it is that if you use, say, the APC backend, you will have it cached across requests. You also get query caching as a bonus (this is not result caching, read the link I provided carefully)!

Resources