Automatically loading models referenced in a template with ember-data - ember.js

I would like to have model binding relationships loaded automatically when referenced in a template. For example, if I have models like this:
App.User = DS.Model.extend
name: DS.attr 'name'
App.Contact = DS.Model.extend
addedBy: DS.belongsTo 'App.User'
and a view like this:
<div>{{contact.addedBy.name}}</div>
it would be really nice if ember-data caught on that it needs to load the User with a primary key in "addedBy". Currently I have to load the User manually with App.User.find(contact.get('addedBy')) and then the template binding updates to display the user's name.
This is a very simple example but in practice I sometimes find myself traversing relationships pretty far. Is there an easy way to automate this?
Thanks folks!

What about side-loading the associated users when serving contacts?
Assuming you are using Rails & active_model_serializers gem, you would have a ContactSerializer like this:
class ContactSerializer < ActiveModel::Serializer
embed :ids, :include => true
#...
has_one :user
end
Doing so, the user will be auto-populated when contact is retrieved.
See documentation.

Turns out that ember-data does exactly what I want by default, and the problem was a bug in my code.
Make sure that the backend for your adapter's findMany() method returns the records in the same order as the argument array of IDs otherwise your DS.hasMany relationships will act very very weird!

Related

Rails: Using Controller as a Model Name

I have a model that is called "controller". I checked the rails reserved terms list and it does not show "controller" as a word not to be used.
The model works fine but when I use the model in a view, the view does not submit the controller attribute back to the controller.
Any idea if "controller" is in fact a reserved word?
Yes controller is reserved in RoR. Even you can use it like this in your views:
#to get controller name:
<%= controller.controller_name %>
#to get action name, it is the method:
<%= controller.action_name %>

Multiple Devise models with unique attributes

Short explanation:
I seek architectural advice and help in implementing multiple Devise models in a single app.
More detailed explanation:
My application needs to perform the following behavior:
There are 3 types of users (Partner, Attendee, Speaker) which have some common fields and some unique ones (also, the fields might have different permissions, i.e. Attendee must have a username whereas the Speaker might have it but they don't have to necessarily fill this field in). And moreover, the different user models must have different associations with other tables in the db.
The users need to be able to log in through single log-in form, but the sign-up forms should be different.
So, my first thought was that I should divide the users by roles using Pundit or declarative_authorization or something, but the users don't really have different roles (i.e. permissions) in the app, they rather have different behavior, they might see different content and stuff, so I continued thinking.
My second though was implementing STI and after reading several articles about it, I tried to do that in code.
I generated a Devise User model by doing rails g devise User and after that ran rails g model Attendee and the same for other two users.
Then, I inherited my models from User:
class Attendee < User
end
My User migration looks like this:
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :type
# Devise stuff ...
..................
t.timestamps null: false
end
And other migrations are like this:
create_table :attendees do |t|
t.string :username
t.string :company_name
t.boolean :subscription
t.timestamps null: false
end
Now I realize it was wrong to create separate tables.
I had to put all the possible fields into the User table, is that correct?
Because now when I try to create any new Attendee or Speaker or Partner in rails console, all of these three models have the exact same fields, those the User model has.
But if I add all the possible fields in the User model, how would I perform validations on field presence?
I've read quite a few articles and questions here on SO, but still can't really wrap my head around how to implement all that.
Anyway, is that a correct way to do what I need?
Could anybody explain me in a detailed way how I should implement this kind of behavior and functionality from start to finish, and how should I work with the models after having implemented them?
PS: here's the history of my migrations and the whole github repo
Update
Remembered another issue that stopped my from doing just role separation:
How should I sign up the different users with different sign-up forms? Different routes? I cannot make the user choose their role from the combobox.
You can create conditional validation rules based on the role, but the first place you need to address this is in the new/edit User form, only showing the allowed fields dynamically based on the role:
class User < ActiveRecord::Base
validates :company, presence: true, if: :is_company?
def is_company
# check for the role
self.role == 'company'
end
end
UPDATE: You can pass an extra parameter to the same registration form and use that to differentiate the type of form you display. That's the nicest way. You can also create separate methods in the UserController -> def register_user, def register_company, def register_xxxx

EmberJs Change name to belongsTo property in model

I'm starting with Ember, and I wanted to know if its possible to do this.
My server model of a book:
Book = {
name: 'string',
author_id: 'number'
}
But in my Ember side, I wanted to have something like this:
Book = {
name: DS.attr('string'),
author: DS.belongsTo('author' , {via: 'author_id'})
}
Is this possible?
Yes, that's possible. You don't define that on the relationship though, you implement transformation behavior in your serializer. So rather than telling Ember that your server calls that relationship something different, you just convert the relationship to the format Ember wants before it's loaded into the store.
For instance, if you're using the RESTSerializer, you can override the keyForRelationship hook.
App.BookSerializer = DS.RESTSerializer.extend({
keyForRelationship: function(key) {
if (key === 'author') {
return 'author_id';
} else {
return key;
}
}
});
This will tell the serializer to get the data for the author relationship from the author_id field in your JSON. It'll also ensure that when it sends JSON back to your server, it converts the author relationship back to the author_id property when serializing.
If you're not using the RESTSerializer, you can probably find the serializer you're using on the Ember Data API documentation page and your serializer will mostly likely have the same method or a very similar method.

ActiveModel::Serializers and Ember Data - Correctly modeling my serializer to be used with Ember Data

In my app, a Post has_many Comments and a Comment belongs_to Post (modeled via the has_one relationship in my serializers).
Since I get the Stack Level Too Deep error message whenever I attempt to model both of these relationships in my serializers, I am wondering if I should keep the has_many associations or the has_one association.
I also have an initializer that embeds :ids and sideloads the data.
Thanks for any help guys. I googled this I swear!
For those relationships, your serializers should look like this:
class PostSerializer < ActiveModel::Serializer
embed :ids
attributes :id # add other attributes here
has_many :comments
end
class CommentSerializer < ActiveModel::Serializer
embed :ids
attributes :id # add other attributes here
has_one :post
end
If you're getting a stack level too deep error, it's most likely from not embedding the ids. Without the ids being embedded it would attempt to embed the comments inside the post, and for every comment, again embed the post, which then embeds the comments again and so on in an infinite loop.
You should also make sure that you're using the DS.ActiveModelSerializer and DS.ActiveModelAdapter in your ember app.

Don't load a relationship

Lets say I have a model like this:
App.User = DS.Model.extend({
attributes : DS.attr('string'),
countries : DS.hasMany('country', { async: true }),
)};
And the server returns the JSON, with a country_idsarray which all works fine, but I don't want to actually load the countries models corresponding to these IDs, which ember-data is doing automatically. Is there any way to stop/suppress this automatic functionality?
Ember Data should load models only if you address to countries field.
If you need only ids try to define country_ids field in model.
UPD:
It seems like *_ids is reserved by framework. So you can ask your server to send this array with another name and define simple attr for this in model.
If you use rails and ActiveModel::Serializer it can be done like this:
class UserSerializer < ActiveModel::Serializer
embed :ids
attributes :id, :attributes
has_many :countries, key: :countries
end
And model:
App.User = DS.Model.extend({
attributes : DS.attr('string'),
countries : DS.attr()
)};