Chris Oliver

Joined

293,020 Experience
93 Lessons Completed
295 Questions Solved

Activity

Hey Thomas,

You'll definitely want some sort of single sign on process. Most of the results will probably come up on google if you search for that. I did a little searching and couldn't find anything really good. Basically you'll want a primary site that can handle the authentication and then send you back securely to the main sites so they can log you in. It's kind of similar to how OAuth works.

You may want to check out CAS whcih is a central authentication service. There's a devise plugin for it (https://github.com/nbudin/devise_cas_authenticatable) but I've never built anything with it. Pretty sure a project like 6 years ago that I worked on used a CAS but I wasn't around when they set it up. I should probably make some screencasts on this at some point. It seems really convoluted from all the tutorials but I'm sure it's simpler than they make it out to be.

I would say try your best to eager load as many of the subrecords as you can so that you're not querying as much. You may be able to cache that in the controller instead of the partial and save some query time that way.

I meant to mention this in the video so thanks for bringing it up! :)

Absolutely correct on that. Normally I would write a test for it, but this is not core functionality to Devise and tests for little tiny things like this don't really add much other than slowing down your test suite. There are still tests that make sure the generators still run correctly so it still works. If the functionality ever got reverted back to the original on accident, it wouldn't be a big deal. You could certainly add a test, but I'd argue how much value you actually get out of it in this case.

I think for resque, you'll need to pass in the tenant into the job as an extra parameter so that you can set the tenant in the beginning.

This is how apartment-sidekiq works https://github.com/influitive/apartment-sidekiq

Sidekiq is probably a better solution anymore than Resque. It's a lot faster and much better supported so if you haven't written too much Resque code, it might be worth switch to using the apartment-sidekiq gem with Sidekiq. It'll take care of passing in and switching to the tenant for you automatically.

Posted in Deploy Ubuntu 14.04 Trusty Tahr Discussion

For security, there's a few things you can do like setup a firewall and only open port 80 or 443 for web, setup fail2ban, and disable password authentication over SSH. You'll want to be careful not to lock yourself out of the server, but the recovery console can still let you in if you do. :) More stuff to checkout https://wiki.ubuntu.com/Bas...

Pingdom is probably the most used one, but there are a bunch if you search for monitoring. I use Pingdom's free service I think.

Posted in Deploy Ubuntu 14.04 Trusty Tahr Discussion

There's a cool little trick that if you change the youtube URL from "youtube.com" to "ssyoutube.com" it will redirect and give you a link to download the video like this:

http://en.savefrom.net/#url...

This might work. You'll have to test it inside the class methods to find out if the Apartment::Tenant is correctly set to verify that it's working. I imagine it would, but you can just print out the current tenant to verify it.

Possibly a better solution would be to loop through the companies inside the methods themselves instead. That would give you a bit more control over setting the tenants.

Hmm that sounds right. Are you able to share an example app that I could take a look at? Not sure I can give you any more pointers without fiddling with some code.

This a good question and is semi-complex so there are a ton of different approaches to it.

One of the ideas that's related to this (which isn't necessarily the right way to go) is Single Table Inheritance. It lets you define a singe "Service" table in your database and then have a "type" associated with it so that you could have ChefService, MusicianService, etc all stored in the same place. I would say this is a bad idea because you're going to have a lot of extra columns on the table that aren't associated with the service, but it's a step in thinking in the right direction.

There are a bunch of different ways you could do this. One option would be to create a bunch of different tables for these and just store them separately. Another would be to create a Service table, and have two other tables "RequiredFields" and "FieldAnswers". You could create the BaseService like normal, and then based upon the "type" column, you could reference the RequiredFields table and look up ones that match that type. You'd have a record for each like

RequiredField (service_type, name, format)

  • service_type: "chef", name: "cuisine", format: "string"
  • service_type: "chef", name: "dietary_type", format: "string"
  • service_type: "chef", name: "max_people", format: "integer"
  • service_type: "musician", name: "genre", format: "string"
  • service_type: "musician", name: "instrument", format: "string"
  • etc

And then this could generate a form dynamically based upon the fields and types. Then when they fill out the form, you can save their results into a FieldAnswers table that stores the RequiredField ID and the answer.

Another option would be to group all these into serialized hashes in a text field. It's somewhat limiting, but could also work.


Also this is where database like Mongo are a bit better suited because you can store a "Service" and have different types of attributes easily included. You don't have to define your data structure ahead of time, but it has plenty of other gotchas that you'll want to look into first. If you're down to learn all that, Mongo might be a good solution for you.

You'll either need to do separate searches and combine the results or index one main model and include the nested models attributes in the index.

Hey Aime! Sorry, I've been meaning to get back to you but have been behind.

Source code: https://github.com/excid3/g...

And searching multiple models works a bit differently. For example, you would want to index and search Post, but the fields you would index should include both the comments and tags. This is what I did for indexing tags in the example.

Another way to do it would be to search those separately and combine the results. Facebook does it this way for example.

Posted in Firefox rendering issues

Hmm, you're right. I would check a couple things:

  1. Make sure you're including any of the browser specific tags that you might be using for newer css styles. Make sure you include any of the -moz ones just in case https://developer.mozilla.org/en-US/docs/Web/CSS/Mozilla_Extensions
  2. Verify your CSS isn't missing any curly braces or anything. For example it looks like .tab-container .etabs works just fine in Chrome but on Firefox that's not getting matched. Seems odd, so maybe the CSS for that specific tag has some error that causes it not to get parsed properly in Firefox.

Turbolinks actually does all of what you're describing with the new partial functionality. I made a video on it on another service that I was fiddling with.

You can check out the video here: https://www.livecoding.tv/video/new-turbolinks-3-features-with-ruby-on-rails/

Posted in Subscriptions with Stripe Discussion

You can swap a lot of the JS out with the Stripe Checkout button. The same process works there. You'd keep the token callback and server-side code. It's pretty much the same minus the form and the JS listener for submit. :)

This is an awesome question. I've dealt with this in the past and I'm also going to be adding a "watched" feature to GoRails. So how do you tackle it efficiently?

There's a bunch of different ways to go about this but they'll all involve caching of some sort.

  1. Easiest option is to simply just render the thumbnails without the "watched" functionality and then change the thumbnail class when the page loads via AJAX. Use JS to gather all the thumbnail video IDs on the page, make one request to the server to see the user's status on each of those, return the result back, and then add a "watched" class to the thumbnails that triggers the CSS to display that.

This would be super easy to build and would be pretty efficient. Basecamp has talked about using this approach in their app in a few places. Super lightweight and also allows you to cache the thumbnails globally. The results of the watched AJAX request can also be cached and you can bust the cache when the user watches a video. This would make it pretty quick and the page load/parsing time should be fast enough that it wouldn't be hugely noticeable.

This approach breaks down when your "watched" AJAX response is slow. Users would see the thumbnail and then some time later it would change to be "watched" which could be an odd user experience. Therefore... option #2.

  1. The second option is to cache the "watched" state of the thumbnail for each video. You can render your page like you mentioned above, but cache the thumbnails and toss the current user in the scope so you can have a cache for each user and their watched status. When they watch a new episode, only the cache for that user and that episode would change.

Basically just doing this around the thumbnails:

<%= cache [current_user, video] do %>
  <% if current_user.watched?(video) %>
  <% else %>
  <% end %>
<% end %>

In both these cases, the best bet will be to make one single query of the user's activity to get all the user's watched videos at once instead of separate queries.

Instead of a bunch of queries hitting the databaselike this:

current_user.activities.where(status: "watched", video: @video).any?

Load them all up, and do a quick lookup instead

@watched_video_ids = Video.joins(:activities).where(activities: {status: "watched", user: current_user}).pluck(:id)

And in your views, you can just check if the video is in the instance variable instead of hitting the database

<% if @watched_videos.include?(video.id) %>
  # watched
<% else %>
<% end %>

In the short term, both of those solutions will be most efficient by loading up all the watched videos at once (until they've watched thousands of videos of course) and then just checking that array rather than going to the database each time.

Your mileage may vary, and the most efficient solution in the long term will really be determined by how usage of your app ends up being. For something like GoRails, there aren't that many episodes so loading up an array of each video ID that you've watched will be pretty quick. For YouTube...that's a whole different story and they'll probably do a much different solution. But they've got the time and money to spare for that. 😉

Posted in Stripe Payments

Always the easy things! 😉

Last night I got tripped up on making a pluralization mistake for like 45 minutes. :)

Posted in Stripe Payments

It sounds like you've got everything but may just need to restart your rails server to pickup the constant in the config file. Have you tried that?