Activity
Posted in How "expensive" are API calls?
In general, API calls are pretty lightweight. They are significantly cheaper requests than regular page views because they don't require you to generate a full page, you only have to render some JSON which is easily generated from Rails. You'll notice most of these requests should complete in a smaller portion of the time that a full page request would take in your Rails logs. An example might be like 50ms to produce the JSON instead of 100ms to produce the full HTML page depending on how complicate your pages are. Of course, this all depends on the work you're doing server-side to make it happen. Some things can be slower like if you have to hit an external API.
There are many ways to optimize as well. For example, in an SPA, if you request a resource (like an Episode) you can pre-load the Likes inside of the JSON so the SPA can handle that all at once. Then when you click "Like" it can do the AJAX request just like I showed in the episode. If you take this approach, it's almost no different than what we did in that episode, except for the fact that the frontend is managed and rendered by the JS. That will make for a significantly slower first page load as it has to download a lot of Javascript the first time, but from there it mostly just needs to request JSON from the server after that.
One big issue with SPAs is that you have to still make these indexible by search engines, therefore requiring you to figure out a way of server-side rendering HTML still to have SEO for your site.
Now having explained all that, these approaches are significantly different. You've changed from producing HTML to JSON and moved a giant amount of logic from the server side to the frontend JS. This might be what you want, but Turbolinks is designed to be a middleground for these two approaches. You get the speed benefits of an SPA while keeping the same HTML the backend produces and writing minimal JS. The other giant benefit of this approach is that with the mobile adapters, you can operate with a smaller team all using the same Rails app HTML responses. The mobile devs get to focus on what they need to make a great experience native on mobile without having to rebuild the entire UI for mobile which is awesome.
Of course, SPAs make a lot of sense when you need to expose an external API for random people to consume. You can use the same API internally as what they would consume externally which is a strong reason for why you might want to go that approach over Turbolinks. Either way you can kill two birds with one stone, just depends on what your end goals are (and how much money you have to invest in a team to build it).
Clearly I should make a video on this asap. :-)
Posted in Any good tutorials on using rbenv?
These are really good questions
1) Nope, bundler will do that for you. However, there will be a global default, so that's why you get the rake error and why you want to run bundle exec rake whatever
instead of just rake whatever
. Bundler handles this separation for you.
2) Not a thing. You can add a .ruby-version
file to your repository if you want to set it to a specific version of Ruby which rbenv will detect and switch to. That's pretty handy if you're working on an old app that needs a specific version of Ruby.
Same as #2, the
.ruby-version
from the repository should do the trick for you, but possibly you will need to make sure you install the proper version of Ruby if you don't have it installed. Each version of Ruby lives entirely on its own, so you get entirely separate sets of gems between versions. You will notice, for example, that Bundler won't exist in your new installs of Ruby and will want to reinstall that.If you want to start fresh, all you'll have to do is install Ruby and bundler and then run
bundle install
in your app directories. That is really all there is to it.
Posted in Migration Issue caused Heroku to fail.
Hmm, that's interesting. I don't actually use Paperclip myself, but I did google that error and find this: http://stackoverflow.com/questions/4528287/paperclip-callbacks-or-simple-processor
Possibly that's the issue you're running into? Sounds like it has something to do with the callbacks defined on the model.
Posted in Pundit scopes
Dmitry,
Without Pundit, you can scope your queries in the controller with @tasks = current_user.department.tasks
so that it always accesses them through the User.
With Pundit, you can setup a scope to reference the Department on the user:
class TaskPolicy < ApplicationPolicy
class Scope < TaskPolicy
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
@scope.where(department_id: @user.department_id)
end
end
end
And use this by saying @tasks = policy_scope(Task)
Posted in In-App Messages Between Users Discussion
Unfortunately that only generates mailers which you can see here: https://github.com/mailboxe...
Posted in In-App Messages Between Users Discussion
Interesting. It looks like it does support it. I don't see that mentioned anywhere that you must use pg or mysql and their example app uses sqlite3: https://github.com/mailboxe...
Absolutely will cover that! :D
Thought it was about time to spruce up the videos. :)
Posted in In-App Navbar Notifications Discussion
Hey Ariff,
Since the notifications include two users (the receiver and the actor) you need to make sure that if a user gets destroyed, then it removes notifications on both sides. What you've written should work, except that you need to give one of the two has_many assocations a different name because the second one overrides the first one. I would rename the second to something like
has_many :sent_notifications, class_name: "Notification", foreign_key: :actor_id, dependent: :destroy
This will give you the association that can still get automatically deleted without overriding the original one. Plus we rename this one so that you can still use the common "current_user.notifications" to get the ones where you are the receiver.
Aweosme! :D
I believe you'll have to make your CoffeeScript class global if you want to do that. More info on that: http://justinreid.com/coffeescript-global-classes/
Posted in In-App Navbar Notifications Discussion
I appreciate it! :)
Posted in In-App Navbar Notifications Discussion
Hey Dan! I'd change it to something like this: https://gist.github.com/exc...
Posted in GoRails Screencast suggestion: Caching
I do have an episode on Fragment caching that is helpful: https://gorails.com/episodes/fragment-caching-and-oembed
The main reason I probably won't cover query caching is because in order for your website to be always up-to-date, you'll have to query the database to find the most recent records. If you cache queries, you won't know that there are new records since you didn't make another query.
The way fragment caching helps is you make the query (which only takes a couple milliseconds) and then you look at the results to see if there are HTML fragments cached for those results. If so, you just send over the HTML fragment as a response instead. This is a lot simpler and gives you the same benefit in performance.
Posted in Subscriptions with Stripe Discussion
Awesome! I also forgot all about koudoku, so I might have to do an episode on that as well in the future.
You're using rescue
without capturing the exception, so you actually lose the error that's happening. If you remove that block, you'll get the exception printed out.
I believe you can't pass a string in there like that to the new method. It only accepts integers http://ruby-doc.org/stdlib-2.3.0/libdoc/date/rdoc/Date.html#method-c-new
Posted in Display user
Hey Nick,
I believe you'll need to actually modify your autocomplete code to render HTML rather than the standard text you pass it.
Here's an example of how you'd include an image in the jQuery autocomplete library: http://stackoverflow.com/a/7896744/277994
Basically you just have to override the default rendering code in the JS so that it can display the image tag rather than the text.
Posted in Subscriptions with Stripe Discussion
Great question and I meant to make a follow up episode talking about that. I will still do that, but here's the gist:
1. You'll need a pricing page that lists the plans. When you click on the link to subscribe, you'll pass the plan ID in the URL to the checkout page.
2. The checkout page will load up the plan based on the ID to verify it exists and is allowed (makes it easy for changing things over time).
3. You'll pass the plan ID as a hidden field during checkout
4. SubscriptionsController's create action will lookup the plan again to verify it and then submits the stripe ID instead of the hardcoded "monthly" value
5. After signing up, you'll link the user to the plan as well so you can use it for your authorization and functionality of your site that they paid for access to.
That should do the trick! I'll try and record a screencast on this very soon as a follow up.
Hmm, that's interesting. I just tried it and it's not doing that for me. There's a user with a birthday in the system as Jan 5, 1980 and it doesn't seem to find nearby results for me.
irb(main):009:0> User.search(where: {birthday: Date.new(1989, 5, 26)}).count
User Search (2.4ms) curl http://localhost:9200/users_development/_search?pretty -d '{"query":{"filtered":{"query":{"match_all":{}},"filter":{"and":[{"term":{"birthday":"1980-01-6"}}]}}},"size":1000,"from":0,"fields":[]}'
=> 0
irb(main):010:0> User.search(where: {birthday: Date.new(1989, 5, 25)}).count
User Search (2.9ms) curl http://localhost:9200/users_development/_search?pretty -d '{"query":{"filtered":{"query":{"match_all":{}},"filter":{"and":[{"term":{"birthday":"1980-01-5"}}]}}},"size":1000,"from":0,"fields":[]}'
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (2, 1)
=> 1