Chris Oliver

Joined

292,890 Experience
93 Lessons Completed
295 Questions Solved

Activity

Posted in Duration of a video in the listing page

Agreed. :) I'm going to update the list to include the durations shortly.

And yeah, my ideal length is 15-20 minutes, but because the audience is a wide range of beginner to advanced Rails devs, it's hard to cover everything in that time. I should probably start splitting episodes up into two parts to handle that better.

Makes sense. Well if you're using friendly_id, the only ID that users will see will be the slug, not the database ID. As long as you don't have a count as part of your slug you'll be fine. You can even have it generate a random string for the slug if you want.

Posted in Is possible to check boolean value by JS?

Yep, something like that could work. That should print out true or false in the data attribute (you can inspect the html to verify) and sure give you back a Javascript boolean you can use when you query for it.

Posted in Just sharing: Squash your migrations

Yeah I think you're correct.

From the Rails guides:

In order to run your tests, your test database will need to have the current structure. The test helper checks whether your test database has any pending migrations. It will try to load your db/schema.rb or db/structure.sql into the test database. If migrations are still pending, an error will be raised. Usually this indicates that your schema is not fully migrated. Running the migrations against the development database (bin/rails db:migrate) will bring the schema up to date.

If there were modifications to existing migrations, the test database needs to be rebuilt. This can be done by executing bin/rails db:test:prepare.

Posted in Just sharing: Squash your migrations

Yeah, db:schema:load will load whatever is in the schema.rb file. You could have migrations that haven't been run yet and as such, they wouldn't show up in your schema or after a load.

Posted in Just sharing: Squash your migrations

Your migrations are just records of changes to the database but that doesn't mean it has recorded all changes to the database correctly (you can write broken migrations), so the schema.rb is actually a generated map of the actual database setup.

The schema is everything that the database currently contains has regardless of what your migrations say. Plus the schema is cached so you can keep track of it independently and use it for quicker setups of databases in development and test environments.

I don't think there's any migration related changes in 5.1, so if it works with 5.0 it should work with 5.1 no problem.

Hmm, my main question is why do you want to hide the ID from the form?

I'd recommend friendly_id. You don't have to override to_param with it and you can simply define the attributes you want as candidates for the ID in case there's some conflicts:

class Restaurant < ActiveRecord::Base
  extend FriendlyId
  friendly_id :slug_candidates, use: :slugged

  # Try building a slug based on the following fields in
  # increasing order of specificity.
  def slug_candidates
    [
      :name,
      [:name, :city],
      [:name, :street, :city],
      [:name, :street_number, :street, :city]
    ]
  end
end

I've used friendly_id for years and it hasn't let me down once. It's what I'm using on GoRails as well for the forum urls too.

Posted in Rail API Knock User Authentication

Hey Anand,

Generally people store the JWTs client side in LocalStorage. It's like a local database stored in the browser so you can just stash it there and retrieve it later. It functions similar to cookies but you have to manually save it yourself rather than the browser taking care of cookie storage automatically for ya.

Posted in How to delete records in a join table?

You'd be best off making a controller for it. Something like

resources :documents do
  resources :document_attachments
end

Then you can have that sub-controller for those DocumentAttachment records and can scope them to the document. And from there you can add the destroy action to lookup the Document, the DocumentAttachment, and then destroy it.

As you might have noticed, deleting files has pretty much nothing to do with Refile itself. Refile installs callbacks so that when you delete the database record, it will automatically delete the file along with it. So really you are doing just normal model deletes and Refile is just coming along for the ride.

I wasn't planning to dive more into it, but I could be persuaded.

As far as multiple models, there's nothing special other than including the acts_as_messageable on them I think. See: https://github.com/mailboxe...

For different conversation types, you can probably add a column to the mailboxer_conversations table for the conversation_type and then you'd just have to create the Conversation record with that extra attribute. You may either need to create conversations directly through Mailboxer::Conversation model or you might do a send_message and then update the Mailboxer::Conversation record with the conversation_type after it has been created. I'm not sure which the best solution would be there but you can experiment with both and see what's cleanest / easiest. All in all that shouldn't be too bad.

I think you have a typo. It's user_signed_in? not user_signed_in. That should do the trick!

if user_signed_in?
  layout 'admin_lte_2'
else 
  layout 'some_other_layout'
end

Sounds like it turned out nicely! And that makes perfect sense for the infinite scroll pagination.

As for when the list is filtered... how about sending both the ID of the item you're moving and the item you moved it before. Then server-side you can look up the position of the second record and then insert just before that. That might work for that case?

Of course, it's always going to be a little weird when looking at a filtered list since the top may not be the real top of the list and that might be confusing to users.

Ah yeah that makes sense. From a usability standpoint, it would feel impossible to drag one of those cards through a big list.

This got me thinking about how Shopify does this. It appears that you can choose the global sort order and if you do a manual sort you get this:

If you choose to sort Manually, you can click any of the products shown to drag it to a new position in the list. The collection will be displayed on your online store under the Featured heading.

That solves the problem of it being awful to try to order only a few products out of say 500. The ones you care about sorting to the top you probably want as "featured" which makes perfect sense.

This kind of gives you the best of both worlds. Simplicity in functionality but the ability to order the ones you do care about. Might be a decent option for solving that problem.

https://help.shopify.com/manual/products/collections/collection-layout#change-the-sort-order-for-the-products-in-a-collection

Great point on sorting a subset @Jacob, although I would imagine you'd possibly need separate sorting indexes for each of those potentially if the same items are in both groups.

@Sean, when you say "obviously isn't scalable" what do you mean by that? You're making a single update for only the affected records which doesn't sound like it will have significant problems. If you drag an item to a different position (say 3 foward) you need to update that record and the other 3 that you moved it past. That's very quick to simply change a column in a few records and should be done all at once in a single database transaction.

A useful gem for this is acts_as_list which will handle all the queries for you and let's you just worry about calling the right methods when a user drags an item. I've used it anytime I need draggable items and it works great. You can also check out how they handle the update queries to adjust the indexes if you want to roll your own.

One question I'd have is how you envision the UI to work when you want to drag an item across pages? Something like how iOS and Android let you hover on the side of the screen to change pages?

Posted in Setup Ubuntu 17.04 Zesty Zapus Discussion

Fantastic! :D

It sometimes depends on what you're using the data for. For example, an email address is something you would want to for sure strip extra whitespace on. However, a forum post doesn't really matter. A little extra before or after space isn't necessarily going to matter when it's displayed in HTML as it probably won't even get reflected in the browser because they're not HTML characters.

As part of assigning an attribute, it makes sense to strip characters then before actually assigning the value.

class User < ApplicationRecord
  def email=(value)
      super(value.strip)
  end
end

That said, I imagine that most of the gems will opt to do a before_validation callback for this so they can take care of the cleanup all in one fell swoop without overriding each and every attribute method on the class. An additional benefit of the callback is that it will be done before every save which means that if the data was inserted in a way that skipped the setter, it would still get stripped correctly. A callback is going to guarantee that runs before every save where setters might not.

For example, this gem uses the callback approach: https://github.com/rmm5t/strip_attributes/blob/master/lib/strip_attributes.rb#L8-L10

On the client is fine, but should never be trusted. Server side processing of params should always be done because it's too easy to get around the JS and submit bad data.

There's also things like TRIM in postgres that you could use for this, but it makes sense to clean up whitespace before it hits the db because you'll usually want it done before you run validations in Ruby to verify the data.

I'd probably say the callback approach is the best place for this. All your validations are run by callbacks so you can have data integrity. Stripping whitespace is something you want to run every single save as well for the same reason, so callbacks fit this really well.

And this is a good reminder, callbacks aren't always bad. When people give out the advice to "avoid callbacks" they're saying you shouldn't jump to that when you want to implement business logic. For example, sending an email after registering with a callback isn't great because you can't turn it off. However, stripping whitespace is different because you'll always want that to run and you do want it closely coupled to your data since it's not business logic, it's for data integrity. Same reason why your validations always run on the validation callback, you always want them to run to keep the integrity of your data. 👍

Keep in mind that a gem like strip_attributes is like 100 lines of code and they've already encountered all the obvious gotchas that you will run into if you implement it from scratch. To me, adding a gem that's that short is totally worth it. If something doesn't work you can just dive in and fix it, and if you were to build your own you'd probably end up with a similar amount of code and having to build your own gem to share it between your apps. At that point you're probably reinventing the wheel a bit unnecessarily just to remove one line from your Gemfile. If it were something more complex, I feel like it'd be worth considering but in this case it's almost too simple not to just grab a gem for it and focus on more important things in your app.

Posted in What text editor are you using for GoRails Forum?

And related thread on the topic as well: https://gorails.com/forum/simple-mde-duplicates#forum_post_3488

There's the code I use on GoRails which I think is working pretty well. I had to do a window popstate clean up as well in addition to the turbolinks before-visit event.

Posted in What text editor are you using for GoRails Forum?

Yessir, using SimpleMDE. I'm fairly happy with it, although there are a few odd things it does like when you hit tab it makes things code blocks and I expect it to highlight the Comment button.

There's an episode on this that I made about Turbolinks + SimpleMDE: https://gorails.com/episodes/turbolinks-simplemde-markdown-editor?autoplay=1

Posted in Autoloading models not working

Ah glad you got that fixed. I was going to reply yesterday and got distracted. I figured that there was something up with the folder naming and the naming of the classes. Rails always expects you to have those names match up which the error tries to tell you, but it can never point out the exact problem.

Usually when you see the error like "Unable to autoload constant Survey::Question, expected /home/gian/repository/capitan/app/models/survey/question.rb to define it" then you know you've made a typo or forgot a module name somewhere.

Glad it's working! 🤘