Jacob Montgomery

Joined

33,740 Experience
33 Lessons Completed
40 Questions Solved

Activity

Posted in Resource on how to do filters with checkboxes

Hi Masud,

If you've ever made a simple search form for a rails app then you've already done everything necessary to make this feature. All these are is a form that submits the selected options to an action which gets passed into a query to get the results.

Check these links:

Couple of more things come to mind to check... make sure all the proper directories exist and that they all have the proper permissions for your server. Since you're manually moving one of the files, you could be running into an issue there. I've forgotten to create remote directories countless times...!

Ok, but did you still verify your upload limit wasn't set too low? Two images can easily be over the 1mb default setting for nginx, for instance, 1 picture from my phone is around 5mb in size... http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size

If file size limits are good to go, then next step would be to figure out what you're using to manage your uploads... Refile / Paperclip / Carrierwave / etc...?

Are you using a 3rd party for file storage, such as Amazon S3?

Have you monitored your error logs to see what the error actually is? You can set your production logs temprarily to debug, then ssh into your production server and tail -f production.log in your console - then try uploading your files. I bet you'll see some sort of error that will help you track your issue down.

Hi Srinivasa,

What size of file are you working with? Your production server probably has file size restrictions in nginx/apache that you may need to tweak.

Check: http://stackoverflow.com/questions/4947107/nginx-upload-client-max-body-size-issue

Great suggestion on acts_as_list Chris, I'll have to save that one!

I wonder if you could do some sort of infinate scroll to keep from having to deal with multiple pages? Although you're still going to have to end up implimenting some sort of search / filter feature - it may save you from having to deal with dragging your selection across paginated results...

Hey Sean,

Interesting problem, I remember features like this from using Joomla when ordering modules, it's a handy feature to have! While I haven't personally implemented something like this yet, I think the way I would approach this is to limit how many items I allow the user to sort, so it becomes similar to a "hot items" or "promoted items" feature. The shop owner probably doesn't really need to manually sort all of their products, and after the first few can go to a normal sort by ID, product name, price, etc...

So you could setup your products table to have your sort_index columns, any products that have a value in the sort_index are considered the "hot items" - any products without will just be regular products. You could then setup a scope, something like scope :hot_items, -> { where.not(sort_index: nil) } that would return all the products that have a value in the sort_index. Since you'd limit how many items can be sorted like this, you really shouldn't run into scaling issues.

As for your pagination issue, you have a few approaches to this. With my suggestion above, you could just display two separate product displays on the same page, one for the hot items, another for the remainder. Or you could use something like Kaminari's array pagination which you could then do two queries to build your final products list object... first query for the hot items, then a second query for the remainder and merge the two queries into a single array of products.

I'm drawing a bit of a blank for an alternative method, hopefully others will chime in with some other ideas!

If I undersand correct, just put the method below private

class ApplicationController < ActionController::Base
  after_action :track_user, only: [:show, :edit] #whatever other actions you want to track

  private

  def track_user
      # do something to track the user
  end
end

Hi naveen,

I haven't actually tested this, but if I'm understanding your question, I believe you can get away with using your ApplicationController to do this since all your controllers should inherit from it.

class ApplicationController < ActionController::Base
  after_action :track_user, only: [:show, :edit] #whatever other actions you want to track

  def track_user
      # do something to track the user
  end
end

Here's a pretty good question on SO that shows 2 methods: http://stackoverflow.com/a/35589063/3670272

Awesome, I'm glad it will work for you! I'll keep an eye out, look forward to seeing the completed site!

Yes, that was a typo Francisco - the repository he shared had the correct association in it. Good catch though, I never even noticed haha :)

Alright, well after a little tinkering I've got a working solution. It could be refactored quite a few times, but I like to first get a solution, then work on refactoring.

scope :that_user_can_create, -> (user_id) {
  user_cards = User.find(user_id).user_cards
  # no need to proceed if user doesn't have any cards
  return nil if user_cards.nil?

  deck_ids = []
  Deck.all.each do |deck|
    deck_card_status = []
    deck.deck_cards.each do |card|
      # check to see if the user has this card
      has_card = user_cards.where(card_id: card.card_id).present?
      deck_card_status << has_card
      # no need to proceed if the user doesn't have this card
      next unless has_card
      has_qty  = user_cards.where(card_id: card.card_id).first.quantity >= card.quantity
      deck_card_status << has_qty
    end

    deck_id = deck_card_status.include?(false) ? '' : deck.id
    deck_ids << deck_id
  end

  Deck.where(id: deck_ids.flatten.uniq)
}

The approach I'm taking is to compare each card in a deck to see if the user meets that cards requirements, if so, that card is flagged true in deck_card_status. deck_card_status then gets checked to see if it includes false, as long as it doesn't then you can include it in the deck_ids. Then, do the final Deck.where(id: deck_ids.flatten.uniq) to get the decks that user can make.

Hey Matias,

Is there any chance you could put together a quick example you could share on github? It's kind of hard to debug without being able to play with the data itself. When you say it's not filtering the quantities correctly, what is the result you're getting and what is the expected result?

Have you tried using some of the other enumerable methods to restructure the query? I remember having some weird results when I started chaining where statements, so I think (as memory serves) I had to switch to using select in that particular scenario... so something like:

DeckCard.select{ |k| decks[:id].includes?(k.id) && deck_cards[:card_id] == user_card.card_id && deck_cards[:quantity] <= user_card.quantity }

But my memory is pretty foggy on that...

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

Hey Lauro,

If I'm not mistaken, I believe he's using SimpleMDE - https://simplemde.com/

Hey Drilon,

It kind of depends on how flexible you need it to be. Will your days only ever need a maximum of 2 operating groups, ie for Monday, group 1 = 9am-11am and group 2 = 1pm-7pm? Or could some days need only one group (Saturday group 1 = 11am-3pm), and/or others need 3+ groups? I don't think your method would be too friendly with varying work groups, but I might be wrong.

Also, how often might the daily work hours need to be updated? Is that something the client will need access to, or would it be something they'd just refer back to you to update if their hours ever change? Will hours vary based on what week it is, or will they be the same regardless of the week #? By week #, I mean there are 52 weeks in a year, the first week in January is week 1, and the last week in December is week 52.

Consider how you're going to be querying for these hours and how you're going to be using those results. This can help figure out the best way to structure your model. Good thing with a setup like this, you can create a constant to test it before actually making the migration... so in your model, just do something like below, then you can start tinkering with the structure to see what works best for your needs.

class ShopOption < ActiveRecord::Base

    # query with: ShopOption::SHOPHOURS[:monday][:open] would return "11:30:00"

    SHOPHOURS = {
            sunday: {
                open: '08:30:00',
                close: '14:30:00',
                status: 'open'
            },
            monday: {
                open: '11:30:00',
                close: '19:30:00',
                status: 'open'
            },
            tuesday: {
                open: '11:30:00',
                close: '19:30:00',
                status: 'open'
            },
            wednesday: {
                open: '11:30:00',
                close: '19:30:00',
                status: 'open'
            },
            thursday: {
                open: '11:30:00',
                close: '19:30:00',
                status: 'open'
            },
            friday: {
                open: '11:30:00',
                close: '19:30:00',
                status: 'open'
            },
            saturday: {
                open: '08:30:00',
                close: '18:30:00',
                status: 'open'
            }
        }

    end
    ```

Posted in why destroy action is called two times.

What really was the fix here, was it closing the modal when the action is called? Was the modal trying to update after the destroy?

Posted in why destroy action is called two times.

Hi naveen,

Could you post your User and UserRole models, mainly the associations you have for them? Also, if you have any before / after actions being called, post those as well. I'm wondering if you have an unnecessary depenedent: destroy or after_destroy in there.

Also, do you have any special function through Geokit that maybe looking to delete something with that user model? Maybe a before/after action? It looks like something is trying to re-query for a User with an id of 12 (which was just deleted) to do something else... if so, whatever that action is either needs to be removed if it's redundant, or moved higher up the chain before the final User object is destroyed.

Geokit is using the domain: localhost
User Load (0.3ms) SELECT users.* FROM users WHERE users.id = 12 LIMIT 1
Completed 404 Not Found in 2ms (ActiveRecord: 0.3ms)

ActiveRecord::RecordNotFound (Couldn't find User with 'id'=12):

Hi Drilon,

I did this for a project a while back, it was a booking app for a salon that had various services all with different appointment durations. I didn't use any gems to manage the time slots since in a single day there can only be so many slots available so the calculations to determine if a slot was available is pretty straight forward.

The general gist to determine if a slot is available is to take the operating hours range and split it into an array of possible appointment slots. So if your shop is open from 9am-5pm, and your appointment has a duration of 1 hour, you can determine that there are potentially 7, 1-hour appointment slots. Now get a list of already booked appointments and remove those times from the array of potential time slots. The time slots left over are now slots that are available that don't overlap with another appointment.

This is the basic function I made that checks if a slot is available or not:

base_time_range.each do |slot|
      overlap = unavailable.map { |booked| (booked[0]...(booked[0] + booked[1].hours)).overlaps?(slot...(slot + time_range[1].hours)) }
     !overlap.include?(true) ? available_slots << slot : ''
end

base_time_range is an array of potential time slots, unavailable is an array of already booked times - iterate over each base_time_range and check if it overlaps the time of an already booked appointment, if it doesn't overlap, add it to the available_slots array.

A couple of things that make appointment bookings a major PITA - if your app will have to deal with people / businesses that have daylight savings time, then you have to be sure that you're checking if the time selected is currently in daylight savings time (dst? method) and adjust accordingly. Also, appointment bookings are extremely susceptible to race conditions, so you need to have a way of holding a time slot while a customer is completing their checkout process.

Also note, I had never done a booking app before, this was my first time doing one and I was still pretty new to ruby/rails so my way may not be all that great - but it's been in production for almost 2 years now and there's been no issues so far, so I guess that's a win!

Oops, sorry I just realized you are submitting the form via javascript.

Your checkout form isn't submitting because of Turbolinks. If you disable turbolinks and revisit the checkout page, you'll see your form submits just fine.

So in turbolinks 5, the "new" way to ensure your scripts are firing is to use $(document).on('turbolinks:load', function() {

So refactored, your JS cart would look like this:

$(document).on('turbolinks:load', function() {

    // checkout process
    $("#checkout").click(function(event) {
        $.get('/checkout/go',
            {
                address_id: $("#address").val(),
                ajax: new Date().getTime()
            },
            function(data, textStatus, xhr) {
                window.location.replace("/orders");
        });
    });

});

Here's an interesting thing I learned that I never knew before... you can't place a form inside an html table, tbody, or tr - it can exist inside td though. Check: http://stackoverflow.com/questions/5967564/form-inside-a-table

So a quick fix to your problem is to simply move the form tag outside your <table>...</table> tags.

Now a bigger issue I noticed with your project is that you're hard coding way too much stuff - for example, all your links are plain html, so instead of using <%= link_to "Some Link", some_link_path %> you're doing <a href="/some_link">Some Link</a> - you really should be using the helpers that rails provides. The same can be said for your form itself... below is what I refactored your form to. You'll need to be sure to put @cart = Cart.new inside your index action in app/controllers/products_controller.rb

<%= form_for(@cart) do |f| %>
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Description</th>
        <th>Price</th>
        <th>Show</th>
        <th>Edit</th>
        <th>Destroy</th>
        <th>Amount</th>
        <th>购买</th>
        <th colspan="5"></th>
      </tr>
    </thead>

    <tbody>
      <% @products.each do |product| %>
        <tr>
          <td><%= product.name %></td>
          <td><%= product.description %></td>
          <td><%= product.price %></td>
          <td><%= link_to 'Show', product %></td>
          <td><%= link_to 'Edit', edit_product_path(product) %></td>
          <td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>

          <%= f.hidden_field :product_id, value: product.id %>
          <% if current_user %>
          <%= f.hidden_field :user_id, value: current_user.id %>
          <% end %>

          <td><%= f.number_field :amount, min: 1, max: 100, value: 1, autofocus: true, required: true %></td>
          <td><%= f.submit "Add to Cart", class: 'btn btn-primary' %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
<% end %>

Interesting... I've only seen this type of behavior caused by Turbolinks.

Is there any way you can create a github repo that reproduces the behavior so I can take a better look?