John Sanchez

Joined

3,820 Experience
15 Lessons Completed
3 Questions Solved

Activity

Posted in Realtime SSH Logs with ActionCable Discussion

Definitely interested in sockets :)

Hi Steve, I see what the problem is. You CSV iterator is built for a has_one or belongs_to relationship.

In a has_one or belongs_to relationship, Active record will pass the object in directly. Which allows you to call something like:

Invoice.first.product # returns object

However, since you have a has_many relationship in your Invoice model, you need to treat the returned value as an array.

For example:

Invoice.first.products # returns an array of objects

You need to change how your iteration works.

First, you're iterating through invoices, not products.

Change all.each do |product| to all.each do |invoice|.

Then, you need to add another iterator because an invoice has_many products. That means, you need to go through each one of those products.

invoice.products.each do |product|

Next, you can place those products into the CSV file.

For example:

class Invoice < ApplicationRecord
  has_many :products, dependent: :destroy

  def self.to_csv
    CSV.generate(headers: true) do |csv|
      csv << attributes = %w{date vendor_name invoice_number title  }

      all.each do |invoice|
               invoice.products.each do |product|
                  csv << invoice.attributes.merge(product.attributes).values_at(*attributes)
               end
      end
    end
  end

Give that a shot and let me know if it works.

Hey Steve, did you add the merge for the title because you weren't seeing the title in your CSV file? What results are you hoping for and what are you receiving?

Hmm I don't think the entry example you mentioned pasted in correctly. Would you be able to try again?

Interesting. Would you please check your rails server logs to see how many "Last Product" lines processed?

In another terminal window, start the rails console via rails console and run Product. Please paste in what that says here.

A stack trace is the entire error displayed in your application log. Here's an example of the stack trace that rails provides in the browser: https://i.stack.imgur.com/yrraB.png

I see what the issue is here. title is not an ActiveRecord Model object. It's an ActiveRecord model attribute for Product. With that said you won't be able to call #attibutes on it like: product.title.attributes. You should already be outputing the title into your CSV file with your code if you remove the merge.

Since, Invoice is the only association you have on your Product model, that's the only other object you can run #attributes on. For instance: product.invoice.attributes.

You're most welcome! :)

Would you be able to post the stack trace that you're receiving with that error?

An undefined method would usually mean a couple of things. Here's what's common:

  1. You have a typo in the association name that you're calling.
  2. That association doesn't yet exist. For example, one of your products doesn't have a title yet. If that's that case, you'd usually receive an "Undefined method 'title' for NilClass" <-- I'm betting this is that case here.

You may be able to find this error by adding a couple of logger lines right below the all.each do |product| line.

For example:

def self.to_csv

    CSV.generate(headers: true) do |csv|
      csv << attributes = %w{date vendor_name invoice_number title  }

      all.each do |product|
            Rails.logger.debug "Last Product: #{product.id}"
            Rails.logger.debug "Last Product Title: #{product.title}"
            csv << product.attributes.merge(product.title.attributes).values_at(*attributes)
      end
    end
 end

This will iterate over each product and allow you to see the last product in the iteration that caused the error.

By the way, what is the title object association for your product? What attributes? What type of association is it? etc.

Posted in Struggling with an association test

Thought 1:

Sounds like you just need to make sure the role and building are created before the user is. Then, in your model, make sure that the user is associated with a default role and building using something like a before_validation.

Then, in your test suite, make sure you create that default role and building before running the test.

Thought 2:

By factory, I'm assuming you're using Factory Girl. You could try using a callback such as before(:create) to create the role and building before the factory is created. Then, use those for the associations.

If the attribute names don't overlap, you could just use a Hash#merge on the attributes before you append them to the CSV.

For example, just change:

all.each do |product|
      csv << product.attributes.values_at(*attributes)
end

To:

all.each do |product|
      csv << product.attributes.merge(product.vendor.attributes).values_at(*attributes)
end

Where product.vendor.attributes would be the attributes for your nested model.

Since you're new to Rails, you may ask why this works.

The product object is an ActiveRecord model object but when you call .attributes on it, Rails will return the values as a Hash. This allows you to use Ruby and Rails Hash methods on it.

You can confirm the object class by opening your Rails console and running .class on the objects.

You can merge as many hashes as you need to for this. Just append .merge to it right before the .values_at method. If you start doing that, I'd recommend cleaning your code up by moving the merges to a new line and storing them in a variable. Then, you can call .values_at on that variable.

Posted in Stripe gems: Koudoku or Payola

I agree with Chris and Jack. I've found that integrating Stripe directly with the api is best. One less dependency for your app to rely on.

Posted in SEEKING FREELANCER - Javascript configuration

Fantastic! No payment needed. :)

Now that's it's working, I'd recommend experimenting with a few things to clean the javascript up and make it unobtrusive.

  1. Try placing the Maps API Src call into the view partial itself. Be sure to place it above the address JS so that it runs first. This way, the maps api only runs on the pages that the map is loaded on.
  2. Try placing the address js back into the javascript file that you had so it's loaded with the rest of the asset pipline. Then, make sure your initMap() call is after the map HTML element is created.
  3. Try placing the initMap() call in a document ready function

If those don't work, no worries. You atleast have it working in the view with what you have now and can move forward with other features for your app.

Posted in SEEKING FREELANCER - Javascript configuration

Hmmm ... okay. I've tested your Javascript code because that would be the only issue here...

I've tested and refactored it outside of rails.

This works as a regular HTML file:

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
        #map { width: 800px; height: 500px; }
    </style>

    <script src="https://maps.googleapis.com/maps/api/js?key=[YOUR_KEY_HERE]"></script>

  </head>
  <body>

    <div id="map"></div>

    <script>
    var map;

    // I'm guessing your address object structure here.
    var addresses = [
      {
        latitude: '30.2669444',
        longitude: '-97.7427778'
      },
      {
        latitude: '31.2669444',
        longitude: '-98.7427778'
      },
      {
        latitude: '29.2669444',
        longitude: '-96.7427778'
      }
    ];

    function initMap() {
        var bounds = new google.maps.LatLngBounds();

        var mapOptions = {
          zoom: 5,
          center: {lat: 30.2669444, lng: -97.7427778},
          mapTypeId: google.maps.MapTypeId.ROADMAP
        }

        var mapDiv = document.getElementById('map')

        map = new google.maps.Map(mapDiv, mapOptions);

         var n = addresses.length;
         for (var i = 0; i < n; i++) {
             var lat = addresses[i].latitude;
             var lng = addresses[i].longitude;
             if (lat == null || lng ==null){
                 console.log(addresses[i].name + " doesn't have coordinates");
             } else {
                 var address = new google.maps.Marker({
                     position: {lat: parseFloat(lat), lng: parseFloat(lng)},
                     title: addresses[i].name,
                     map: map
                     });

            bounds.extend(address.position);
        }
      }

      map.fitBounds(bounds);
    }
    // Make sure you call the initMap function
    initMap();
    </script>

  </body>
</html>

You may want to try model something similar in your rails view.

A couple of notes here:

  1. Make sure you have CSS that sets your height and width of the map element.
  2. Make sure you actually call your initMap() function.
  3. You don't need to add 'center' to your mapOptions object but I did it anyway.
  4. I moved the map api call to the header again. Feel free to do so.
  5. replace [YOUR_KEY_HERE] with your Google API key

Posted in SEEKING FREELANCER - Javascript configuration

Hmm. I just reordered a few things to load in the right order. I haven't tested your code...

Try this. Any errors in the console?

<div id="map"></div>

<script>
var addresses = <%= raw @addresses.to_json %>;

function initMap() {
    var bounds = new google.maps.LatLngBounds();
    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 5
        });

     var n = addresses.length;
     for (var i = 0; i < n; i++) {
         var lat = addresses[i].latitude;
         var lng = addresses[i].longitude;
         if (lat == null || lng ==null){
             console.log(addresses[i].name + " doesn't have coordinates");
         } else {
             var address = new google.maps.Marker({
                 position: {lat: parseFloat(lat), lng: parseFloat(lng)},
                 title: addresses[i].name,
                 map: map
                 });

        bounds.extend(address.position);
    }
  }

  map.fitBounds(bounds);
}
</script>

<script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV["GOOGLE_MAPS_API_KEY"] %>"></script>

Posted in SEEKING FREELANCER - Javascript configuration

I don't mean add an event listener. I mean add it to the view file itself. You can organize your JS to be unobtrusive later. You want the code to run after the element is created. Place the function and the function call in a script tag beneath the map html element. Once you've done that, copy and paste the code you have for your view here.

Posted in SEEKING FREELANCER - Javascript configuration

I can either have googlemaps working (if I move the javascript include tag out of the head and to the end of the body tag) in which case, the rest of my javascript doesnt work.

Yeah, don't do that. :)

Leave the JS tag in the header.

Try loading your address.js on the page itself instead. That's right, place it at the bottom of your views file.

I tried removing turbolinks. I commented out all the files that refer to turbolinks and pushed that to production

Leave turbolinks commented out until you figure this out.

I also dont get a map - just a blank white square where the map should be.

That means that the element is rendering correctly. Great!

You probably don't see the map because your javascript in your address.js file is being called before your element is rendered in the DOM.

Make sure your address.js code is after your map element in your view. That way, the javascript code runs after the element has been created.

I intentionally removed those two lines (underscore and gmaps). They were required when I was trying to use gmaps4rails gem but are not required to just use javascript. I couldnt get gmaps for rails gem to work. I found a solution that worked (although I couldnt set a zoom level) to render a map without that gem - so I removed the requirment for those 2 lines.

If you're no longer using it, I would just delete those lines.

In my opinion, if writing the code out is simple, try not to use gems. Everytime you add a gem, you add a dependency that could break and cause a LOT of headace in the future when trying to update rails.

Posted in SEEKING FREELANCER - Javascript configuration

Oh, by the way, your application.js file isn't quite right...

You have:

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require jquery-fileupload/vendor/jquery.ui.widget
//= require jquery-fileupload/jquery.iframe-transport
//= require jquery-fileupload/jquery.fileupload
//= require bootstrap-sprockets
//= require moment
//= require bootstrap-datetimepicker
//= require pickers
// require underscore
// require gmaps/google
//= require markerclusterer
//= require cocoon
//= require cable
//= require_tree .

Not that you're missing the equal signs on

// require underscore
// require gmaps/google

It should be:

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require jquery-fileupload/vendor/jquery.ui.widget
//= require jquery-fileupload/jquery.iframe-transport
//= require jquery-fileupload/jquery.fileupload
//= require bootstrap-sprockets
//= require moment
//= require bootstrap-datetimepicker
//= require pickers
//= require underscore
//= require gmaps/google
//= require markerclusterer
//= require cocoon
//= require cable
//= require_tree .

That could be your issue right there...

Posted in SEEKING FREELANCER - Javascript configuration

Don't listen to people like that.

I mean't that you should comment out or remove turbolinks until your JS is working. If your other libraries are working, comment them out and just leave the one you're working on uncommented.

Your StackOverflow post is has become extremely long and in my opinion all over the place. Rather than me trying to figure out where you're at, tell me where you're at.

What's currently working and not working on your production environment app? Is it just Google Maps that's not working?

Posted in Add paywall functionality to app

You're welcome! Good luck! :)

Posted in Add paywall functionality to app

Hi Stan, if you're looking for something simple, I'd recommend just creating a session and using that session as a counter. The following is a pure Ruby implmentation. You'll want to make some adjustments for your Rails app. I haven't tested it within Rails yet but I think you'll get the point.

# Rails has a sessions object that you can use. the next line creates an object to represent it.
session = {}

# You typically have your content in a database and can pull it out as an object. The following will represent that object.
content = {}

# The following represents the values of your content.
content[:title] = 'Title of Content'
content[:content] = 'Display content'

# Create your pay wall session counter
session[:pay_wall] ||= 1

# Run your conditional to check the counter
if session[:pay_wall] >= 5
    puts 'Add Pay Wall code here'
elsif session[:pay_wall] >= 1
    session[:pay_wall] += 1
    puts content[:content]
else
    session[:pay_wall] = 1
    puts content[:content]
end

# Test the value of your session
puts session[:pay_wall]

Resources you may find interesting on the topic of sessions:
http://www.justinweiss.com/articles/how-rails-sessions-work/
http://api.rubyonrails.org/v5.0.1/classes/ActionDispatch/Integration/Session.html

Posted in SEEKING FREELANCER - Javascript configuration

Hmm ... I'm only briefly able to read your SO post don't have the time right now to go through it all the way.

From what I understand, the problem is that your code works on Development but not in Production? Is that right?

It might be a stupid question, but have you tried disabling turbolinks? Here's a link to how http://blog.flightswithfriends.com/post/53943440505/how-to-disable-turbolinks-in-rails-4 if you haven't tried it.

Sometimes, turbolinks will mess with you like you've mentioned in your post. If you haven't tried it, see if disabling it helps at all.

As I outlined in this post, the js files (except for google maps) don't work in production if I have the javascript include tag in the head. I only arrived at this solution after a long, expensive session on codementor. I can't afford another session to find out how to solve the problems that this solution has created. I also didn't get an explanation as to the fundamental reason why this change is necessary. The rails guides suggest including it there so I don't understand why, for the most part, moving it to the end of the body tag is a solution that gets the js to work in the production environment. This breaks the address js though, so it isn't the right solution

By reading through your JS, the reason that you need to load it at the bottom is because of the "getElementById" in the init()

var map = new google.maps.Map(document.getElementById('map'), {

By loading that at the top, the script might not find the element because it's loading before the element is created.

You could also try wrapping those in a document.onload handler to have it load after the DOM is done loading.

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

© 2020 GoRails, LLC. All rights reserved.