1

really, it just quit loading one day. I've been on Rails 5.0.0.beta3 the whole time. logs don't show any attempts to load anything from assets/ . had everything set up just as docs instruct. Gemfile:

gem 'sass-rails', '~> 5.0'
gem 'bootstrap-sass', '~> 3.3.6'

application.scss:

@import "bootstrap-sprockets";
@import "bootstrap";

application.js

//= require jquery
//= require jquery-ui
//= require bootstrap-sprockets
//= require jquery_ujs
//= require turbolinks
//= require_tree .

also, tried adding require 'bootstrap-sass' to config.ru. it didn't help.

UPDATE:

so, it looks like bootstrap dies every time I try to add a module to my application controller, like so:

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  include SomeModule
end

any ideas?

here is the module:

module BeforeOrAfter
  attr_accessor :past
  attr_accessor :future

  require "date"
  def initialize
    @future = []
    @past = []
  end

  def before_or_after(event)
    if event < DateTime.now
      @past << event.id
    else
      @future << event.id
    end
  end
end
sivanes
  • 713
  • 1
  • 13
  • 22

1 Answers1

1

The error you're getting is due to overriding initialize on ApplicationController without calling super as follows:

require "date"
module BeforeOrAfter
  attr_accessor :past
  attr_accessor :future

  def initialize(*args)
    @future = []
    @past = []
    super
  end

  def before_or_after(event)
    if event < DateTime.now
      @past << event.id
    else
      @future << event.id
    end
  end
end

On the other hand, after clarifying your question, it looks like this is entirely unnecessary. You have an Enumerable (e.g. an array) of objects representing events and you just want to split them into past and future events. The Enumerable#partition method is ideal for this purpose: it takes a block and splits the input into two arrays, one with all the items which match the condition and another with all the items that do not. So, my recommendation is:

  • Delete the module you were attempting to include
  • Add partition code to the controller where you need to split the events.

Assuming your array is called events and contains ActiveRecord-like objects with a time field:

(@past, @future) = events.partition { |event| event.time < Time.current }

And that's it! You now have @past and @future available in your view. If the events really are ActiveRecord models you could take it a step further and add this to the Event class:

def past?
  self.time < Time.current
end

And then change your controller as follows:

(@past, @future) = events.partition(&:past?)
# equivalent to the following:
# (@past, @future) = events.partition { |event| event.past? }

If you need to do this across a range of controllers and want to encapsulate the functionality you don't need a separate module, just define a function in your ApplicationController to be called by each controller.

# application_controller.rb
def prepare_events(events)
  (@past, @future) = events.partition { |event| event.time < Time.current }
  events
end

# widgets_controller.rb
def index
  @widgets = Widget.all
  prepare_events(@widgets)
end

If you always populate the same instance variable regardless of your collection's contents you can even make it an after_filter in the application controller:

after_filter :prepare_events
def prepare_events
  (@past, @future) = @resources.partition { |event| event.time < Time.current }
  true
end

To make it possible to add events multiple times you would need to join the arrays. The simplest way would be to add them and split them again.

# application_controller.rb
def prepare_events(events)
  events = events + @past + @future if @past
  (@past, @future) = events.uniq.partition { |event| event.time < Time.current }
  true
end
Owen
  • 1,527
  • 11
  • 14
  • I've been going over this post for past few days. All this stuff like multi-threading, per-request arrays is very new to me. The purpose of this array is, for several controllers, to organize events' datetimes into past and future categories to pass into views, so that the two categories can be displayed separately. – sivanes Aug 04 '16 at 21:25
  • If it is used on a per-request basis, you would be better off doing something like this: `(@past, @future) = events.partition { |e| e < DateTime.now }`. Let me know and I will update the answer with more detail. – Owen Aug 05 '16 at 00:11
  • can you give me an example of when it is or isn't a per-request scenario? as I imagine it, when rails generates a view, it tries to fulfill a request for past events and future events. in that process, it would build those two arrays in the cache. would that make it per-request? – sivanes Aug 05 '16 at 02:33
  • Yes - unless you are expecting to collect events from multiple users and track them at the same time. I shall type up an answer that incorporates this - it would help if you can provide a code sample for when you use the methods from the included module. – Owen Aug 05 '16 at 02:36
  • Ultimately, I want to use the before_or_after method in my erb files for separating data into Past and Future categories. I haven't started on that part yet, but in this related thread (I still haven't gotten this module to work just in Rails console) http://stackoverflow.com/questions/38665645/nilclass-error-when-passing-an-argument I show how I've tried to test it out. – sivanes Aug 05 '16 at 02:52
  • Nice! And I want to apply the exact same logic to multiple controllers, such as Artist, Venue, Event, etc, all of which have the datetime attribute. Do I just repeat it? Because that's why I began writing the module in first place. – sivanes Aug 05 '16 at 15:39
  • could you respond to my previous comment when you get a chance? The solution is still incomplete this way. Thank you! – sivanes Aug 08 '16 at 18:27
  • 1
    I've expanded on the example to show you only need one function which can be put in `ApplicationController`. You could also do it in a module and include that module. The main difference is you would provide the whole collection instead of one object at a time, so you only need to call it once and it sets both target variables. – Owen Aug 08 '16 at 22:59
  • Another clarification. In my case, I will make calls such as `prepare_events(artist)` and `prepare_events(venue)`, then `(@past, @future) = artist.events.partition ...` inside the method and `artist.events` below that (if I'm handling an artist's events). The result that I get is just the future events, not two separate arrays. – sivanes Aug 09 '16 at 22:34