TL

Joined

1,640 Experience
8 Lessons Completed
0 Questions Solved

Activity

Let's say I have 400GB of uploaded images inside a 800GB VPN machine. So we're confortably using 50% of storage.

Even tough we have our hosting's backup enabled, we want to have an extra backup sitting on S3, just because we can't get enough of backups right?

So, using `backup` gem, we are already sucessfully backing up Mysql and storing it on S3, so now we want to create a second model to backup these files.

The question is: if we create a zipped file with all theses images prior to uploading to S3, we would run out of disk space right?

Is there a way to just upload all 400gb of images to S3 and incrementally update it, on a daily basis, without having to duplicate all files (zipped or not) on hard drive?

Is RSync better suited for this, in which case I should opt out of S3 and buy a node (like in Digital Ocean) ?

What are our options?
Thanks a lot Chris, exactly what we needed.
Do you guys know any gems to quickly build a 'Whats new' page like the one in https://www.hatchbox.io/announcements?

Posted in MessageBus Gem

Hi Chris. It seems MessageBus is a nice and much simpler alternative to WebSockets/ActionCable. Could you add one episode on this on the pipeline? 

Got here trough searching on google. devise_group does sound super useful!! Thanks a lot for finding this.

Thanks to Chris nice tutorials, we just rewrote a slow interface in our app to use Vue.js. Now Rails is just generating the JSON to be consumed by Vue.js in the view.

What I'm trying to achieve is to generate a cached JSON response using read_multi or fetch_multi, so all Conversations (there are 20 on each pagination) are loaded on a single call to memcached.

Le'ts say I have a model called Conversation, that belongs to an user, to a tourist, to a property, and it also has many replies.

class Conversation
  belongs_to :user
  belongs_to :tourist
  belongs_to :property
  has_many :replies
    has_many :holidays

    def generate_json
        {

        tourist: {
          name: tourist.name,
          email: tourist.email,
        property: {
          id: property.id,
          image_url: property.pictures.first.try(:image).try(:url,:thumb),
          property_code: property.property_code,
          title: property.title_br,
        },
        recent_replies: replies.last(5).map(&:generate_json) 
      }
    end


end

For the has_many associations, I simply use touch: true in the other side of the association, so model Reply is a belongs_to :conversation, touch: true, which takes care of updating Conversation's updated_at if it changes and the cache is automatically updated.

But every time I try to cache a model like this (wether in a view fragment or, in this case, in a JSON response) I end up with a huge and complex cache key due, mainly, to the belongs_to association on the cached model. Something like this for example:

Rails.cache.fetch(self.cache_key, self.user.cache_key, self.tourist.cache_key, self.property.cache_key) do
   ... generates the JSON for this model
end

Justin Weiss has a nice tutorial (altough a bit complex) of how to cache complicated JSON responses (https://www.justinweiss.com/articles/a-faster-way-to-cache-complicated-data-models/) but as far as I could understand he's using manually expiring cache keys.

I'm a little bit lost at this point. How would you guys implement caching for this type of JSON structure?

One idea is to use just the self.cache_key in the cache key for the Conversation, (1) rely on touch: true for the has_many associations and (2) write manual after_commit :touch_conversations for the belongs_to associations, something like this:

model Tourist

    has_many :conversations
    after_commit :touch_conversations

    def touch_conversations
        self.conversations.update_all(updated_at: Time.now)
    end

end

The problem with this approach is that some users already got + 200k conversations for example. Updating them all takes at least 4 seconds in my tests, and I'm afraid interfaces will start to get sluggish over time.

Posted in Tutorials on recommendation engines

Thanks a lot guys!

Posted in Tutorials on recommendation engines

Hi Chris,

I searched for videos on recommendation itens but couldn't find any.

We run a real estate website and would love to provide similarities recommendations (like "users that viewed this property also liked ...". There seems to be a handful of gems to acomplish this, but it's not trivial and it would be great to have a tutorial with your expertise. Any plans for a video like this?

Imagine a travel website where you have HotelOwners and Tourists. When they start a conversation, the app creates a join model named Conversation using has_many through. It's a classic many to many association:

class HotelOwner
  has_many :tourists, through: :conversations
  has_many :conversations
end

class Tourist
  has_many :hotel_owners, through: :conversations
  has_many :conversations
end

class Conversation
  belongs_to :hotel_owner
  belongs_to :tourist
end

Now we can use hotel_owner.tourists and tourist.hotel_owners. Also, the join model Conversation is also being used to keep some state on that association between them both (like, HotelOwner comments on Tourist and vice-versa).

But now we need a Reservation model. My initial ideia was this:

class Reservation
  belongs_to :hotel_owner
  belongs_to :tourist
end

But we also need to create the Conversation join model, since app logic requires that there cannot be a Reservation without a previous Conversation, even if a blank one. Also, the hotel_owner notes on tourist and vice-versa should be kept there and need to exist if a reservation exists.

After thinking about using manual callbacks to manually create the join model Conversation, I read that it would not be a good idea to add a belongs_to :conversation on Reservation because it could lead to database inconsistencies (like the problem if reservation.conversation.tourist pointed to a different tourist then reservation.tourist .. there should be a single source of truth to this association right?)

I then had the idea of using Conversation as a proxy to Reservations, like this:

class HotelOwner
  has_many :tourists, through: :conversations
  has_many :conversations
  has_many :reservations, through: :conversations
end

class Tourist
  has_many :hotel_owners, through: :conversations
  has_many :conversations
  has_many :reservations, through: :conversations
end

class Conversation
  belongs_to :hotel_owner
  belongs_to :tourist
  has_many   :reservations
end

class Reservation
  has_one :hotel_owner, through: :conversation
  has_one :tourist,     through: :conversation
  belongs_to :conversation
end

Since there is no belongs_to through in Rails to use in Reservation, other posts in SO suggest using has_one trough instead, just like I did above.

The problem is that conversation has_many reservations, and does not belong_to a reservation (like it does belong to a Tourist and HotelOwner).

It's not only semantics that bother me. If I do hotel_owner.reservations.create(tourist: Tourist.last), it does create the Reservation, but the join model Conversation is not created, leaving reservation.conversation nil.

After a simple hotel_owner.reload, hotel_owner.reservations return nil.

What is the correct database design and Rails association model for something like this?

Congrats for #200 Chris, you are putting out quality stuff here. Cheers!

Chris I'm a new subscriber and I'm loving Go Rails. The content is really usefull for real-world applications.

After implementing the "Like" feature in my website, I came across a doubt that keeps popping up in my apps.

Let's say I have a Favorites Controller that responds with create.js.erb and destroy.js.erb.

It all works great, but then let's say I have a different view called "Favorites" like the one you have here (https://gorails.com/users/:user_id/favorites) and I want to add a link to remove from favorites there.

The difference is that, in this view, when I remove something from favorites, I want the video to disappear from the list, and not only the heart to become gray, so the jQuery in the js.erb response is different.

It sounds silly to repeat the controller code and views, so I assume we should keep things DRY and use the same controller and actions.

But the question is: how to deal with this scenario when the HTML for the js.erb response is different, since we're dealing with 2 different views?

Right now I'm solvin this by passing data: {params: {source: 'name_of_the_view} } in the link_to, and using that params[:source] in the js.erb to render the correct jQuery accordingly using if/else statements. Do you agree with this solution? Is there another best practice?

Posted in Liking Posts Discussion

Hi Chris, just subscribed, really nice stuff here. Regarding this tutorial, I have a question about caching: how would you implement this like feature without having to use `current_user` as the cache key (which obviously would defeat the purpose of the cache in the first place) ? Would you recommend using a gem like `render_async` to do this?

logo Created with Sketch.

Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

© 2021 GoRails, LLC. All rights reserved.