In Rails, thanks to the incredible ActiveRecord library, we can do things like this:
bear = Bear.find(id)
bear.eyes = 'blue'
bear.friends += 1
bear.save
And the changes are then saved into the database.
In Meteor I can do this:
bear = Bears.findOne({});
bear.eyes = 'blue';
bear.friends++;
The two changes made are only made to the local copy in memory. As far as I can see the changes cannot be persisted without calling a Mongo update statement.
Bears.update({
_id: bear._id,
$inc: { friend: 1 },
eyes: 'blue'
});
I love Meteor, it is pretty amazing... but this would seem to be a big step backwards if it cannot be done.
Is there some way to persist bear as we used to do in Rails / ActiveRecord?
As of this writing, meteor does not include an ORM in its core packages. There is, however, a community package called astronomy which implements ActiveRecord-style models. The complete documentation can be found here.
Recommended reading:
To create a simple model layer using the tools that the core packages provide, have a look at this article.
To read a summary of where the community is heading, check out this issue on the official guide repo.
Related
I am currently planning a complex application using ruby on rails and ember.js. What I have seen about ember-data so far is that it caches records automatically; post.comments will first result in a Ajax-call to fetch all comments for the given post, but if the user visits the same route the next time, it will just fetch the records from the store-cache.
The problem is: What if another user added a comment to this post? How to tell ember it has to reload its cache because something changed?
I already thought about a solution using websockets to tell clients which stuff to reload - but I don't think this is best-practice. And in addition, I can't imagine this isn't a common problem, so I am wondering what other developers are doing to solve this issue.
I tried to implement model updating in (experimental) chat application. I have used SSE: ActionController::Live on server side (Ruby on Rails) and EventSource on client side.
Simplified code:
App.MessagesRoute = Ember.Route.extend({
activate: function() {
if (! this.eventSource) {
this.eventSource = new EventSource('/messages/events');
var self = this;
this.eventSource.addEventListener('message', function(e) {
var data = $.parseJSON(e.data);
if (data.id != self.controllerFor('messages').get('savedId')) {
self.store.createRecord('message', data);
}
});
}
}
});
App.MessagesController = Ember.ArrayController.extend({
actions: {
create: function() {
var data = this.getProperties('body');
var message = this.store.createRecord('message', data);
var self = this;
message.save().then(function (response) {
self.set('savedId', response.id);
});
}
}
});
The logic is simple: I'm getting each new record from EventSource. Then, if record was created by another client, the application detects it and new record being added to store using ember-data's createRecord. Suppose this logic may have some caveats, but at least it serves well as 'proof of concept'. Chat is working.
Full sources available here: https://github.com/denispeplin/ember-chat/
I have something to say about reloading: you probably don't want to perform full reloading, it's resource-consuming operation. Still, your client side needs some way to know about new records. So, getting new records one-by-one via SSE is probably the best option.
If you just want to get rid of caching you can force a reload every time user navigates to comments route. But this largely depends on what you are trying to acheieve, I hope comments is just an example.
If you want your ui to get updated automagically with changes in server, you need some communication with server, some polling mechanism like websocket or polling from a webworker. Then you may reload the list of changed records sent from server. You are probably on the right track with this.
You can as well take a look at the orbitjs standalone library that integrates well with Ember. This is more useful if you require local storage as well and got to manage the multiple data sources.
This is really a common problem with any web application, no matter what framework you are using. From my point of view, there are two main options. One: You have a service that polls the server to check to see if there are any changes that would require you to reload some of your models, have that service return those model IDs and refresh them. The other option is as you suggested, using a websocket and pushing notifications of model changes/new models themselves.
I would opt to actually just send the comment model itself, and push it into the Ember store and the associated post object. This would reduce the need to hit the server with a hard refresh of your model. I am currently using this method with my Ember app, where there is an object that contains overview data based on all the models in my app, and when a change is made in the backend, my websocket server pushes the new overview data to me application.
UPDATE:: I meant for this to be a comment, not an answer, oh well.
I've had this same issue with mobile app development. While websockets seemed like the first answer, I was worried about scalability issues with limited server resources. I decided to stick with the Ajax call to fetch newly modified records. This way server resources are only used if the user is active. However, as others pointed out, returning all comments every single time you need data makes your cacheing useless and is slow. I suggest updating your rails server to accept an optional timestamp. If the timestamp is not supplied, then every comment is retrieved. If a timestamp is supplied, then only return comments where the updated_at column is >= the supplied timestamp. This way, if no comments were added or modified since your last call, then you quickly get back an empty list and can move on. If results are returned, you can then merge them with your existing list and show the updated comments.
Example of fetching newly created or modified comments
if params.has_key?(:updated_since)
comments = Post.find(params[:id]).comments.where("updated_at >= ?", params[:updated_since])
else
comments = Post.find(params[:id]).comments
end
TMDB.org recently made a change to their API which removes the capability to browse their database.
My Rails app used to use the tmdb-ruby gem to browse the TMDB database, but this gem only worked with v2.0 of the API, which is now defunct.
TMDB.org recommends using this gem, and since it is forked from the gem I previously used, it makes it a bit easier.
My PostgreSQL database is already populated with data imported from TMDB when v2.0 was still extant and when I could use the browse feature.
How can I now use the find feature (ie: #movie = TmdbMovie.find(:title => "Iron Man", :limit => 1) ) to find a random movie, without supplying the title of the Movie.
This is my rake file which worked with the older gem.
I would like to know how to have it work the same way but whilst using the find instead of the browse.
Thanks
I don't think find is what you need in order to get what you want (getting the oldest movies in the database and working its way up to the newest movie). Looking at the TMDb API documentation, it looks like they now have discover that may have replaced the browse that you used to use.
I don't see discover anywhere in Irio's ruby-tmdb fork, but it looks like most of the specific methods they have (like TmdbMovie.find) call a generic method Tmdb.api_call.
You should be able to use the generic method to do something like:
api_return = Tmdb.api_call(
"discover/movie",
{
page: 1,
sort_by: 'release_date.asc',
query: '' # Necessary because Tmdb.api_call throws a nil error if you don't specify a query param value
},
"en"
)
results = api_return["results"]
results.flatten!(1)
results.uniq!
results.delete_if &:nil?
results.map!{|m| TmdbMovie.new(m, true)} # `true` tells TmdbMovie.new to expand results
If this works, you could even fork Irio's fork, implement a TmdbMovie.discover method supporting all the options and handling edge cases like TmdbMovie.find does, and send them a pull request since it just looks like they haven't gotten around to implementing this yet and I'm sure other people would like to have this method as well :)
this question has been asked here already but it's quite some time ago. Does anyone know if Rails has any support for Microsoft Access? I'd need to import and export data every few weeks and would really like to avoid exporting/importing csv files.
Thanks!
It's worth noting that there's an mdb gem for Ruby. It requires mdbtools to be installed.
Add to your Gemfile:
gem 'mdb'
Usage is pretty straightforward, tables are basically lists of hashes:
require 'mdb'
database = Mdb.open('workshops_handouts_inactive_database.mdb')
table = database[:MainData]
results = table.select { |rec| rec[:"Schedule Type"] == "MU1" }
puts results.first
{:"Container Number"=>"17", :Location=>"1f6", :Department=>"tx", ...
I don't think ActiveRecord support exists for MS Access, though.
the win32OLE class allows you to retrieve data from Microsoft Acess you can find the docs here
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/win32ole/rdoc/WIN32OLE.html
I'm currently trying my hand at developing a simple web based game using rails and Mongoid. I've ran into some concurrency issues that i'm not sure how to solve.
The issue is i'm not sure how to atomically do a check and take an action based upon it in Mongoid.
Here is a sample of the relevant parts of the controller code to give you an idea of what i'm trying to do:
battle = current_user.battle
battle.submitted = true
battle.save
if Battle.where(opponent: current_user._id, submitted: true, resolving: false).any?
battle.update_attribute(:resolving, true)
#Resolve turn
A battle is between two users, but i only want one of the threads to run the #Resolve turn. Now unless i'm completely off both threads could check the condition one after another, but before setting resolving to true, therefore both end up running the '#Resolve turn' code.
I would much appreciate any ideas on how to solve this issue.
I am however getting an increasing feeling that doing user synchronization in this way is fairly impractical and that there's a better way altogether. So suggestions for other techniques that could accomplish the same thing would be greatly appreciated!
Sounds like you want the mongo findAndModify command which allows you to atomically retrieve and update a row.
Unfortunately mongoid doesn't appear to expose this part of the mongo api, so it looks like you'll have to drop down to the driver level for this one bit:
battle = Battle.collection.find_and_modify(query: {oppenent: current_user._id, ...},
update: {'$set' => {resolving: true})
By default the returned object does not include the modification made, but you can turn this on if you want (pass {:new => true})
The value returned is a raw hash, if my memory is correct you can do Battle.instantiate(doc) to get a Battle object back.
i happen to be kinda picky when programming something big. I try to find the best way to do it it terms of speed and complexity. Since i've been learning Rails the previous 3 months, i try to find the best techniques for everything. I would like to ask you how you would go about writing some code like this :
#defender = User.find_by_id(user_id)
#attacker = current_user.clone
#attacker_starting_attribs = current_user
#defender_starting_attribs = #defender.clone
#defenderWeapon = #defender.getEquippedWeapon
#attackerWeapon = #attacker.getEquippedWeapon
#combat = Combatant.fight(#attacker, #defender)
This code is about the battle outcome between two persons in a browser game. The code works well, but i've some problems in terms of good coding. In fact, i know that my code is bad here, that's why i ask you what a better version would be. Let me explain what happens in this code.
#defender is given by user_id, so i guess that this part is needed. Now, in #attacker i'm cloning the current_user. The reason is that Rails works on objects and current_user will be changed inside Combatant.fight. I need both the new hp and the old hp and that is why i'm cloning the object. The defender and attacker starting attribs illustrate that concept. Now, i get the weapons in instance variables, so that i can get their information inside the final view.
However, the weapons are needed inside the fight function and i execute the same getEquippedWeapon twice again inside fight(). I was not so comfortable with something like fight(#attacker, #defender, #attacker_weapon, #defender_weapon), but i don't also like the idea of repetition. So, i would like an opinion on that.
#combat is a hash containing the result of the combat. Fight happens and i get that hash back in the view.
I'm not pleased with my coding on that stage and i want your opinion. How would you do it ? Is there maybe a design pattern for that ? Please tell me your opinion.
Thanx :)
I'm finding it difficult to completely understand what you're trying to do. I get the gist of it though (2 people fighting). I won't be able to provide an answer yet, but hopefully this gets the ball rolling:
From the code you provided, #attacker_starting_attribs and #defender_starting_attribs aren't being used.
As far as "good techniques", I try to stay as OO as possible. Instead of
Combatant.fight(#attacker, #defender), I would do #attacker.fight(#defender)
As a ruby convention, method names are underscored. In your case, .get_equipped_weapon instead of .getEquippedWeapon, or even better .equipped_weapon.
Anyways, I bet if you provided more code, you'd get more answers.