profile
viewpoint
Scott González scottgonzalez York, PA http://nemikor.com I once used the GitHub API just to set this bio.

cerebris/jsonapi-resources 2169

A resource-focused Rails library for developing JSON:API compliant servers.

fnagel/jquery-ui 595

A fork of jQuery UI: WIP branches, legacy Selectmenu Widget (branch: selectmenu) and an accessible version of jQuery UI Tabs (outdated, branch: tabs accessability)

JSFoundation/standards 246

Giving web developers a voice in the standards process

scottgonzalez/better-diff 9

The diff tool of the future

rdworth/jquery 3

jQuery JavaScript Library

scottgonzalez/Aloha-Editor 2

World’s most advanced Editor gives you a complete new experience when editing. It’s faster than existing technology and offers unprecedented opportunities.

scottgonzalez/amplify 2

AmplifyJS

cerebris/jsonapi-resources-site 1

Source for the JSONAPI::Resources site

conservancy/reimbursement-requester 1

A simple online application to submit travel reimbursement requests for a backend system using Ledger-CLI

issue closedcerebris/jsonapi-resources

Related Resources do not appear to sort by their default sort criteria

class Foo < JSONAPI::Resource

    has_many :bar

end

class Bar < JSONAPI::Resource

    attributes :position

     self.default_sort
        [{field: :position, direction: :asc}]
    end

end

I would expect

GET /foos/1/bars

to be sorted by position in ascending order, however they appear to be sorted by primary key.

My work around for the time being is to override records_for_bars and have it return a sorted relationship.

Let me know if there is anything I can do to help.

.joe

closed time in a month

joegaudet

issue closedscottgonzalez/node-wordpress

getPosts pagination

Is there a way to get more than the first page of posts? I have a wordpress site that has 26 posts, and I only get back 10 records from getPosts().

closed time in a month

konsumer

issue commentscottgonzalez/node-wordpress

getPosts pagination

Use offset for pagination: https://codex.wordpress.org/XML-RPC_WordPress_API/Posts#Parameters_2

konsumer

comment created time in a month

Pull request review commenttommy-russoniello/pantry-buddy

Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:items) do |table|+      table.decimal(:added_sugar)+      table.decimal(:calcium)+      table.decimal(:calories)+      table.decimal(:carbs)+      table.decimal(:cholesterol)+      table.decimal(:fat)+      table.decimal(:fiber)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron)+      table.decimal(:magnesium)+      table.decimal(:monounsaturated_fat)+      table.string(:name, null: false)+      table.decimal(:niacin)+      table.decimal(:phosphorus)+      table.decimal(:polyunsaturated_fat)+      table.decimal(:potassium)+      table.decimal(:protein)+      table.decimal(:riboflavin)+      table.decimal(:saturated_fat)+      table.decimal(:sodium)+      table.decimal(:sugar)+      table.decimal(:thiamin)+      table.decimal(:trans_fat)+      table.string(:upc)+      table.decimal(:vitamin_a)+      table.decimal(:vitamin_b6)+      table.decimal(:vitamin_b12)+      table.decimal(:vitamin_c)+      table.decimal(:vitamin_d)+      table.decimal(:vitamin_e)+      table.decimal(:vitamin_k)+      table.decimal(:zinc)+      table.timestamps+      table.index(%i[upc], unique: true)

We'll still want this, but we can wait until later to add MySQL and the index.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

Add initial entities

+class ItemService+  NUTRITION_DATA_COLLECTION_RETRY_DURATION = 1.month.freeze++  class << self+    def find_or_create_item_from_upc(upc)+      item = Item.find_by(upc: upc)+      if item+        if item.edamam_id+          date = item.nutrition_data_collection_failed_at+          return item if !date || date > NUTRITION_DATA_COLLECTION_RETRY_DURATION.ago++          create_data_from_fdc(item)+        else+          create_data_from_edamam(item)+        end++        item.reload+      else+        new_item = create_data_from_fdc(upc)+        create_data_from_edamam(new_item || upc)+      end+    end++    private++    def create_data_from_edamam(value)+      if value.is_a?(Item)+        item = value+        upc = item.upc+      else+        upc = value.to_s+      end++      data = Edamam.get_data_from_upc(upc, nutrients: item.nil?)+      return unless data++      health_label_ids = HealthLabel+        .ids+        .values_at(*data[:health_labels].map { |health_label| health_label.downcase.to_sym })+        .compact++      custom_measurement_unit_names =+        data[:measurement_units].except(*MeasurementUnit.standard.keys)++      custom_measurement_units =+        MeasurementUnit.where(name: custom_measurement_unit_names.keys).to_a+      new_measurement_unit_names =+        custom_measurement_unit_names.keys - custom_measurement_units.map(&:name)++      begin+        ApplicationRecord.transaction do+          new_measurement_unit_names.each do |new_measurement_unit_name|+            custom_measurement_units << MeasurementUnit.create!(+              name: new_measurement_unit_name,+              uri_fragment_suffix: custom_measurement_unit_names[new_measurement_unit_name]+            )+          end++          item ||= Item.create!(+            name: data[:name],+            upc: upc,+            **data[:nutrients]+          )++          item.update!(+            grams_per_tablespoon: data[:grams_per_tablespoon],+            health_label_ids: health_label_ids+          )++          custom_measurement_units.each do |custom_measurement_unit|+            ItemMeasurementUnit.create!(+              grams: Edamam.get_grams_per_measurement_unit(+                edamam_id: data[:edamam_id],+                measurement: custom_measurement_unit.uri_fragment_suffix+              ),+              item: item,+              measurement_unit_id: custom_measurement_unit.id+            )+          end+        end++        item+      rescue StandardError+        nil+      end+    end++    def create_data_from_fdc(value)+      if value.is_a?(Item)+        item = value+        upc = item.upc+      else+        upc = value.to_s

Yeah, let's drop this.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

Add initial entities

+module Fdc+  API_HOST = 'api.nal.usda.gov'.freeze+  API_KEY = ENV.fetch('FDC_API_KEY')+  SEARCH_PATH = '/fdc/v1/foods/search'.freeze++  class << self+    def get_data_from_upc(upc)+      data = send_request(+        host: API_HOST,+        method: :get,+        name: 'UPC lookup',+        path: SEARCH_PATH,+        query: { query: upc }+      )&.dig('foods')&.find { |food| food['gtinUpc'] == upc }++      return unless data++      nutrients_data = data['foodNutrients'].map do |nutrient_data|+        nutrient = nutrient_mappings[nutrient_data['nutrientId'].to_s]+        next unless nutrient++        value =+          case nutrient_data['unitName']+          when 'G'+            nutrient_data['value']+          when 'MG'+            nutrient_data['value'] / 1_000+          when 'UG'+            nutrient_data['value'] / 1_000_000+          when 'IU'+            international_units_to_grams(nutrient_data['value'], nutrient)+          when 'KCAL'+            nutrient_data['value']+          end++        value /= 100 if value

Let's add a comment about the data being for 100 grams.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

Add initial entities

+class ItemService+  NUTRITION_DATA_COLLECTION_RETRY_DURATION = 1.month.freeze++  class << self+    def find_or_create_item_from_upc(upc)+      item = Item.find_by(upc: upc)+      if item+        if item.edamam_id+          date = item.nutrition_data_collection_failed_at+          return item if !date || date > NUTRITION_DATA_COLLECTION_RETRY_DURATION.ago++          create_data_from_fdc(item)+        else+          create_data_from_edamam(item)+        end++        item.reload+      else+        new_item = create_data_from_fdc(upc)+        create_data_from_edamam(new_item || upc)+      end+    end++    private++    def create_data_from_edamam(value)+      if value.is_a?(Item)+        item = value+        upc = item.upc+      else+        upc = value.to_s+      end++      data = Edamam.get_data_from_upc(upc, nutrients: item.nil?)+      return unless data++      health_label_ids = HealthLabel+        .ids+        .values_at(*data[:health_labels].map { |health_label| health_label.downcase.to_sym })+        .compact++      custom_measurement_unit_names =+        data[:measurement_units].except(*MeasurementUnit.standard.keys)++      custom_measurement_units =+        MeasurementUnit.where(name: custom_measurement_unit_names.keys).to_a+      new_measurement_unit_names =+        custom_measurement_unit_names.keys - custom_measurement_units.map(&:name)++      begin+        ApplicationRecord.transaction do+          new_measurement_unit_names.each do |new_measurement_unit_name|+            custom_measurement_units << MeasurementUnit.create!(+              name: new_measurement_unit_name,+              uri_fragment_suffix: custom_measurement_unit_names[new_measurement_unit_name]+            )+          end++          item ||= Item.create!(

We should saving to the database here since we're going to save to the database immediately after this as well.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

Add initial entities

+module Edamam+  API_HOST = 'api.edamam.com'.freeze+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_PATH = '/api/food-database/nutrients'.freeze+  UPC_LOOKUP_PATH = '/api/food-database/parser'.freeze++  class << self+    def get_data_from_upc(upc, nutrients: false)+      upc_lookup_data = send_request(+        host: API_HOST,+        method: :get,+        name: 'UPC lookup',+        path: UPC_LOOKUP_PATH,+        query: { upc: upc }+      )&.dig('hints', 0)++      return unless upc_lookup_data++      food_data = upc_lookup_data['food']++      measurement_data = upc_lookup_data['measures']+      measurement_units = measurement_data.map do |measure|+        [measure['label'], measure['uri'].match(/^#{MEASUREMENT_URI_PREFIX}([a-z_]+)$/)[1]]+      end.compact.to_h++      edamam_id = food_data['foodId']+      volumetric = measurement_units.key?('Tablespoon')+      response = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: measurement_uri(volumetric ? 'tablespoon' : 'gram'),+              foodId: edamam_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        host: API_HOST,+        method: :post,+        name: 'UPC data',+        path: NUTRITION_DATA_PATH+      )+      return unless response++      if volumetric+        grams_per_tablespoon = get_weight_from_nutrition_data_response(response)+        return unless grams_per_tablespoon+      end++      if nutrients+        response_nutrients = response['totalNutrients']++        divisor = grams_per_tablespoon || 1+        calories = cast_decimal(response_nutrients.dig(nutrient_mappings[:calories], 'quantity'))+        calories /= divisor if calories

Are there cases where we don't get calories back?

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

Add initial entities

+class ItemService+  NUTRITION_DATA_COLLECTION_RETRY_DURATION = 1.month.freeze++  class << self+    def find_or_create_item_from_upc(upc)+      item = Item.find_by(upc: upc)+      if item+        if item.edamam_id+          date = item.nutrition_data_collection_failed_at+          return item if !date || date > NUTRITION_DATA_COLLECTION_RETRY_DURATION.ago++          create_data_from_fdc(item)+        else+          create_data_from_edamam(item)+        end++        item.reload+      else+        new_item = create_data_from_fdc(upc)+        create_data_from_edamam(new_item || upc)+      end+    end++    private++    def create_data_from_edamam(value)+      if value.is_a?(Item)+        item = value+        upc = item.upc+      else+        upc = value.to_s+      end++      data = Edamam.get_data_from_upc(upc, nutrients: item.nil?)+      return unless data++      health_label_ids = HealthLabel+        .ids+        .values_at(*data[:health_labels].map { |health_label| health_label.downcase.to_sym })+        .compact++      custom_measurement_unit_names =+        data[:measurement_units].except(*MeasurementUnit.standard.keys)++      custom_measurement_units =+        MeasurementUnit.where(name: custom_measurement_unit_names.keys).to_a+      new_measurement_unit_names =+        custom_measurement_unit_names.keys - custom_measurement_units.map(&:name)++      begin+        ApplicationRecord.transaction do+          new_measurement_unit_names.each do |new_measurement_unit_name|+            custom_measurement_units << MeasurementUnit.create!(+              name: new_measurement_unit_name,+              uri_fragment_suffix: custom_measurement_unit_names[new_measurement_unit_name]+            )+          end++          item ||= Item.create!(+            name: data[:name],+            upc: upc,+            **data[:nutrients]+          )++          item.update!(+            grams_per_tablespoon: data[:grams_per_tablespoon],+            health_label_ids: health_label_ids+          )++          custom_measurement_units.each do |custom_measurement_unit|+            ItemMeasurementUnit.create!(+              grams: Edamam.get_grams_per_measurement_unit(+                edamam_id: data[:edamam_id],+                measurement: custom_measurement_unit.uri_fragment_suffix+              ),+              item: item,+              measurement_unit_id: custom_measurement_unit.id+            )+          end+        end++        item+      rescue StandardError+        nil+      end+    end++    def create_data_from_fdc(value)+      if value.is_a?(Item)+        item = value+        upc = item.upc+      else+        upc = value.to_s

Why do we need to cast?

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

Add initial entities

+class Item < ApplicationRecord+  has_many :item_health_labels+  has_many :item_measurement_units++  has_many :health_labels, through: :item_health_labels+  has_many :measurement_units, through: :item_measurement_units++  validates :name, presence: true++  static_attribute :edamam_id, once_set: true+  static_attribute :fdc_id, once_set: true+  static_attribute :upc++  def self.nutrients+    %i[

memoize

tommy-russoniello

comment created time in 2 months

issue closedscottgonzalez/node-wordpress

How to make post creating synchronous?

Have no idea how to force cycle to work in order, one by one.

`var wordpress = require( "wordpress" );

var client = wordpress.createClient({ url: "localhost/test", username: "root", password: "12345" });

for(let x = 0; x < 1000; x++){ client.newPost({ title: x, content: x, status: 'publish' }, function( error, file ) { }) }`

Problem

Cycle working not in order. Not all posts have been created.

closed time in 2 months

jalamba4everkisa

issue commentscottgonzalez/node-wordpress

How to make post creating synchronous?

Please research asynchronous programming.

jalamba4everkisa

comment created time in 2 months

pull request commentscottgonzalez/spawnback

Guard if child.stdout or child.stderr are null

Thanks. Sorry for the delay in merging. This has been released in v1.0.1.

kenrick95

comment created time in 2 months

created tagscottgonzalez/spawnback

tagv1.0.1

Simplified process spawning with buffered output in a callback

created time in 2 months

push eventscottgonzalez/spawnback

Kenrick

commit sha df1b5a48fae8f9cc20b3c7e096f115ba0d67b03c

Guard if `child.stdout` or `child.stderr` are `null` `child.stdout` and `child.stderr` could be `null` if `'inherit'` is passed to `child_process`'s spawn options. Closes gh-1

view details

Scott González

commit sha 7102b72bbf827cc9c812f7f6a4409db1dac968d4

1.0.1

view details

push time in 2 months

PR closed scottgonzalez/spawnback

Guard if child.stdout or child.stderr are null

child.stdout or child.stderr could be null if 'inherit' is passed to child_process's options.stdio

+11 -7

0 comment

1 changed file

kenrick95

pr closed time in 2 months

issue closedscottgonzalez/node-wordpress

Sorry, this file type is not permitted for security reasons.

Hi guys, I do an upload job but it returns me error,

Error: XML-RPC fault: Could not write file my_file (Sorry, this file type is not permitted for security reasons.).

Here is my code

Snip25630424_5

I've found a solution on the internet that I can put a code

define(‘ALLOW_UNFILTERED_UPLOADS’, true);

into the config.php

This solution can solve the issue but almost comments I've read don't recommend to use this solution due to the security issue.

Is there another solution to solve. Or I can go this way without any concern ?

closed time in 2 months

sucheep-s

issue commentscottgonzalez/node-wordpress

Sorry, this file type is not permitted for security reasons.

That's really up to you, but I will say that I used ALLOW_UNFILTERED_UPLOADS for all jQuery sites.

sucheep-s

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  API_HOST = 'api.edamam.com'.freeze+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_PATH = '/api/food-database/nutrients'.freeze+  UPC_LOOKUP_PATH = '/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: measurement_uri(measurement),+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        host: API_HOST,+        method: :post,+        name: 'measurement data',+        path: NUTRITION_DATA_PATH+      )+      get_weight_from_nutrition_data_response(data)&.to_d

This should already be cast to the correct data type before it's returned.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  API_HOST = 'api.edamam.com'.freeze+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_PATH = '/api/food-database/nutrients'.freeze+  UPC_LOOKUP_PATH = '/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: measurement_uri(measurement),+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        host: API_HOST,+        method: :post,+        name: 'measurement data',+        path: NUTRITION_DATA_PATH+      )+      get_weight_from_nutrition_data_response(data)&.to_d+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(+        host: API_HOST,+        method: :get,+        name: 'UPC lookup',+        path: UPC_LOOKUP_PATH,+        query: { upc: upc }+      )&.dig('hints', 0)++      return unless upc_lookup_data++      food_data = upc_lookup_data['food']+      return unless food_data++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name++      measurement_data = upc_lookup_data['measures']+      measurement_units =+        if measurement_data+          measurement_data.map do |measure|+            match_data = measure['uri'].match(/^#{MEASUREMENT_URI_PREFIX}([a-z]+)$/)+            next unless match_data

This also seems unlikely.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  API_HOST = 'api.edamam.com'.freeze+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_PATH = '/api/food-database/nutrients'.freeze+  UPC_LOOKUP_PATH = '/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: measurement_uri(measurement),+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        host: API_HOST,+        method: :post,+        name: 'measurement data',+        path: NUTRITION_DATA_PATH+      )+      get_weight_from_nutrition_data_response(data)&.to_d+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(+        host: API_HOST,+        method: :get,+        name: 'UPC lookup',+        path: UPC_LOOKUP_PATH,+        query: { upc: upc }+      )&.dig('hints', 0)++      return unless upc_lookup_data++      food_data = upc_lookup_data['food']+      return unless food_data++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name++      measurement_data = upc_lookup_data['measures']+      measurement_units =+        if measurement_data+          measurement_data.map do |measure|+            match_data = measure['uri'].match(/^#{MEASUREMENT_URI_PREFIX}([a-z]+)$/)+            next unless match_data++            [measure['label'], match_data[1]]+          end.compact.to_h+        else+          {}+        end++      body = {+        ingredients: [+          {+            quantity: 1,+            measureURI: measurement_uri('tablespoon'),+            foodId: food_id+          }+        ]+      }+      request_data = {+        body: body.to_json,+        headers: { 'Content-Type': 'application/json' },+        host: API_HOST,+        method: :post,+        name: 'nutrition data',+        path: NUTRITION_DATA_PATH+      }+      response = send_request(request_data)++      grams_per_tablespoon = get_weight_from_nutrition_data_response(response)

Why are we making this request unconditionally? We already know whether tablespoons are a supported measurement.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  API_HOST = 'api.edamam.com'.freeze+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_PATH = '/api/food-database/nutrients'.freeze+  UPC_LOOKUP_PATH = '/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: measurement_uri(measurement),+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        host: API_HOST,+        method: :post,+        name: 'measurement data',+        path: NUTRITION_DATA_PATH+      )+      get_weight_from_nutrition_data_response(data)&.to_d+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(+        host: API_HOST,+        method: :get,+        name: 'UPC lookup',+        path: UPC_LOOKUP_PATH,+        query: { upc: upc }+      )&.dig('hints', 0)++      return unless upc_lookup_data++      food_data = upc_lookup_data['food']+      return unless food_data++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name++      measurement_data = upc_lookup_data['measures']+      measurement_units =+        if measurement_data

Have you come across any food that doesn't have measurement data? That seems like it wouldn't happen.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  API_HOST = 'api.edamam.com'.freeze+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_PATH = '/api/food-database/nutrients'.freeze+  UPC_LOOKUP_PATH = '/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: measurement_uri(measurement),+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        host: API_HOST,+        method: :post,+        name: 'measurement data',+        path: NUTRITION_DATA_PATH+      )+      get_weight_from_nutrition_data_response(data)&.to_d+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(+        host: API_HOST,+        method: :get,+        name: 'UPC lookup',+        path: UPC_LOOKUP_PATH,+        query: { upc: upc }+      )&.dig('hints', 0)++      return unless upc_lookup_data++      food_data = upc_lookup_data['food']+      return unless food_data++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name

This guard seems unnecessary.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:items) do |table|+      table.decimal(:added_sugar)+      table.decimal(:calcium)+      table.decimal(:calories)+      table.decimal(:carbs)+      table.decimal(:cholesterol)+      table.decimal(:fat)+      table.decimal(:fiber)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron)+      table.decimal(:magnesium)+      table.decimal(:monounsaturated_fat)+      table.string(:name, null: false)+      table.decimal(:niacin)+      table.decimal(:phosphorus)+      table.decimal(:polyunsaturated_fat)+      table.decimal(:potassium)+      table.decimal(:protein)+      table.decimal(:riboflavin)+      table.decimal(:saturated_fat)+      table.decimal(:sodium)+      table.decimal(:sugar)+      table.decimal(:thiamin)+      table.decimal(:trans_fat)+      table.string(:upc)+      table.decimal(:vitamin_a)+      table.decimal(:vitamin_b6)+      table.decimal(:vitamin_b12)+      table.decimal(:vitamin_c)+      table.decimal(:vitamin_d)+      table.decimal(:vitamin_e)+      table.decimal(:vitamin_k)+      table.decimal(:zinc)+      table.timestamps+      table.index(%i[name])

This isn't going to help us since we won't be doing searches for exact values. A fulltext index is the only useful index to use here.

tommy-russoniello

comment created time in 2 months

CommitCommentEvent

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_URL = 'https://api.edamam.com/api/food-database/nutrients'.freeze+  UPC_LOOKUP_URL = 'https://api.edamam.com/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement_name:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: "#{MEASUREMENT_URI_PREFIX}#{measurement_name.parameterize.underscore}",+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        method: :post,+        name: 'measurement data',+        url: NUTRITION_DATA_URL+      )+      get_weight_from_nutrition_data_response(data)+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(method: :get, name: 'UPC lookup', url: "#{UPC_LOOKUP_URL}?upc=#{upc}")+        &.dig('hints')+        &.first++      return unless upc_lookup_data&.is_a?(Hash)++      food_data = upc_lookup_data['food']+      return unless food_data&.is_a?(Hash)++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name++      measurement_data = upc_lookup_data['measures']+      measurement_units =+        if measurement_data&.is_a?(Array)+          measurement_data.map { |measure| measure['label'] if measure&.is_a?(Hash) }.compact+        else+          []+        end++      body = {+        ingredients: [+          {+            quantity: 1,+            measureURI: "#{MEASUREMENT_URI_PREFIX}tablespoon",+            foodId: food_id+          }+        ]+      }+      request_data = {+        body: body.to_json,+        headers: { 'Content-Type': 'application/json' },+        method: :post,+        name: 'nutrition data',+        url: NUTRITION_DATA_URL+      }+      response = send_request(request_data)++      grams_per_tablespoon = get_weight_from_nutrition_data_response(response)+      unless grams_per_tablespoon+        body[:ingredients].first[:measureURI] = "#{MEASUREMENT_URI_PREFIX}gram"+        request_data[:body] = body.to_json+        response = send_request(request_data)+      end++      nutrients = response['totalNutrients']+      return unless nutrients++      divisor = grams_per_tablespoon || 1+      nutrients_data = nutrient_mappings.map do |nutrient, code|+        nutrient_data = nutrients[code]+        value =+          if nutrient_data+            case nutrient_data['unit']+            when 'g'+              cast_decimal(nutrient_data['quantity']) / divisor+            when 'mg'+              cast_decimal(nutrient_data['quantity']) / divisor * 1_000+            when 'µg'+              cast_decimal(nutrient_data['quantity']) / divisor * 1_000_000+            else+              nil+            end+          end++        [nutrient, value]+      end.to_h.merge(calories: cast_decimal(nutrients.dig('ENERC_KCAL', 'quantity')))++      {+        food_id: food_id,+        grams_per_tablespoon: grams_per_tablespoon,+        health_labels: response['healthLabels'],+        measurement_units: measurement_units,+        name: name,+        nutrients: nutrients_data+      }+    end++    private++    def cast_decimal(value)+      Kernel.Float(value).to_d+    rescue ArgumentError, TypeError+      nil+    end++    def get_weight_from_nutrition_data_response(data)+      return unless data&.is_a?(Hash)++      data = data['ingredients']+      return unless data&.is_a?(Array)++      data = data.first+      return unless data&.is_a?(Hash)++      data = data['parsed']+      return unless data&.is_a?(Array)++      data = data.first+      return unless data&.is_a?(Hash)++      data['weight'] unless data['status'] == 'MISSING_QUANTITY'

Well, none of that matters when the last property we dig is weight and that would never exist if the data wasn't valid. But also, we shouldn't be guarding random broken data coming back.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:items) do |table|+      table.decimal(:added_sugar)+      table.decimal(:calcium)+      table.decimal(:calories)+      table.decimal(:carbs)+      table.decimal(:cholesterol)+      table.decimal(:fat)+      table.decimal(:fiber)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron)+      table.decimal(:magnesium)+      table.decimal(:monounsaturated_fat)+      table.string(:name, null: false)+      table.decimal(:niacin)+      table.decimal(:phosphorus)+      table.decimal(:polyunsaturated_fat)+      table.decimal(:potassium)+      table.decimal(:protein)+      table.decimal(:riboflavin)+      table.decimal(:saturated_fat)+      table.decimal(:sodium)+      table.decimal(:sugar)+      table.decimal(:thiamin)+      table.decimal(:trans_fat)+      table.string(:upc)+      table.decimal(:vitamin_a)+      table.decimal(:vitamin_b6)+      table.decimal(:vitamin_b12)+      table.decimal(:vitamin_c)+      table.decimal(:vitamin_d)+      table.decimal(:vitamin_e)+      table.decimal(:vitamin_k)+      table.decimal(:zinc)+      table.timestamps+      table.index(%i[upc], unique: true)+    end++    create_table(:measurement_units) do |table|+      table.string(:name, null: false)+      table.timestamps+    end++    create_table(:item_measurement_units) do |table|+      table.integer(:grams, null: false)+      table.string(:item_id, null: false)+      table.bigint(:measurement_unit_id, null: false)+      table.timestamps+      table.index(+        %i[item_id measurement_unit_id],+        name: 'ix_item_measurement_units_on_item_id_and_measurement_unit_id',+        unique: true+      )+    end++    add_foreign_key(:item_measurement_units, :items)+    add_foreign_key(:item_measurement_units, :measurement_units)++    create_table(:health_labels) do |table|+      table.string(:name, null: false)+      table.timestamps+    end++    create_table(:item_health_labels) do |table|+      table.bigint(:health_label_id, null: false)+      table.bigint(:item_id, null: false)+      table.timestamps+      table.index(%i[health_label_id item_id], unique: true)

If we don't have a use case for it, we shouldn't have the index.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class MeasurementUnit < ApplicationRecord+  validates :name, presence: true, uniqueness: { case_sensitive: false }++  static_attribute :name++  class << self+    def standard+      return @standard if @standard++      standard_names = [+        'Ounce',+        'Gram',+        'Pound',+        'Kilogram',+        'Pinch',+        'Liter',+        'Fluid Ounce',+        'Gallon',+        'Pint',+        'Quart',+        'Milliliter',+        'Drop',+        'Cup',+        'Tablespoon',+        'Teaspoon'

Why are these in such an odd order? Let's group by type then system.

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_URL = 'https://api.edamam.com/api/food-database/nutrients'.freeze+  UPC_LOOKUP_URL = 'https://api.edamam.com/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement_name:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: "#{MEASUREMENT_URI_PREFIX}#{measurement_name.parameterize.underscore}",+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        method: :post,+        name: 'measurement data',+        url: NUTRITION_DATA_URL+      )+      get_weight_from_nutrition_data_response(data)+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(method: :get, name: 'UPC lookup', url: "#{UPC_LOOKUP_URL}?upc=#{upc}")+        &.dig('hints')+        &.first++      return unless upc_lookup_data&.is_a?(Hash)++      food_data = upc_lookup_data['food']+      return unless food_data&.is_a?(Hash)++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name++      measurement_data = upc_lookup_data['measures']+      measurement_units =+        if measurement_data&.is_a?(Array)+          measurement_data.map { |measure| measure['label'] if measure&.is_a?(Hash) }.compact+        else+          []+        end++      body = {+        ingredients: [+          {+            quantity: 1,+            measureURI: "#{MEASUREMENT_URI_PREFIX}tablespoon",

helper method

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_URL = 'https://api.edamam.com/api/food-database/nutrients'.freeze+  UPC_LOOKUP_URL = 'https://api.edamam.com/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement_name:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: "#{MEASUREMENT_URI_PREFIX}#{measurement_name.parameterize.underscore}",+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        method: :post,+        name: 'measurement data',+        url: NUTRITION_DATA_URL+      )+      get_weight_from_nutrition_data_response(data)+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(method: :get, name: 'UPC lookup', url: "#{UPC_LOOKUP_URL}?upc=#{upc}")+        &.dig('hints')+        &.first++      return unless upc_lookup_data&.is_a?(Hash)++      food_data = upc_lookup_data['food']+      return unless food_data&.is_a?(Hash)++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name++      measurement_data = upc_lookup_data['measures']+      measurement_units =+        if measurement_data&.is_a?(Array)+          measurement_data.map { |measure| measure['label'] if measure&.is_a?(Hash) }.compact+        else+          []+        end++      body = {+        ingredients: [+          {+            quantity: 1,+            measureURI: "#{MEASUREMENT_URI_PREFIX}tablespoon",+            foodId: food_id+          }+        ]+      }+      request_data = {+        body: body.to_json,+        headers: { 'Content-Type': 'application/json' },+        method: :post,+        name: 'nutrition data',+        url: NUTRITION_DATA_URL+      }+      response = send_request(request_data)++      grams_per_tablespoon = get_weight_from_nutrition_data_response(response)+      unless grams_per_tablespoon+        body[:ingredients].first[:measureURI] = "#{MEASUREMENT_URI_PREFIX}gram"+        request_data[:body] = body.to_json+        response = send_request(request_data)+      end++      nutrients = response['totalNutrients']+      return unless nutrients++      divisor = grams_per_tablespoon || 1+      nutrients_data = nutrient_mappings.map do |nutrient, code|+        nutrient_data = nutrients[code]+        value =+          if nutrient_data+            case nutrient_data['unit']+            when 'g'+              cast_decimal(nutrient_data['quantity']) / divisor+            when 'mg'+              cast_decimal(nutrient_data['quantity']) / divisor * 1_000+            when 'µg'+              cast_decimal(nutrient_data['quantity']) / divisor * 1_000_000+            else+              nil+            end+          end++        [nutrient, value]+      end.to_h.merge(calories: cast_decimal(nutrients.dig('ENERC_KCAL', 'quantity')))++      {+        food_id: food_id,+        grams_per_tablespoon: grams_per_tablespoon,+        health_labels: response['healthLabels'],+        measurement_units: measurement_units,+        name: name,+        nutrients: nutrients_data+      }+    end++    private++    def cast_decimal(value)+      Kernel.Float(value).to_d+    rescue ArgumentError, TypeError+      nil+    end++    def get_weight_from_nutrition_data_response(data)+      return unless data&.is_a?(Hash)++      data = data['ingredients']+      return unless data&.is_a?(Array)++      data = data.first+      return unless data&.is_a?(Hash)++      data = data['parsed']+      return unless data&.is_a?(Array)++      data = data.first+      return unless data&.is_a?(Hash)++      data['weight'] unless data['status'] == 'MISSING_QUANTITY'+    end++    def nutrient_mappings+      {+        added_sugar: 'SUGAR.added',+        calcium: 'CA',+        carbs: 'CHOCDF',+        cholesterol: 'CHOLE',+        fat: 'FAT',+        fiber: 'FIBTG',+        iron: 'FE',+        magnesium: 'MG',+        monounsaturated_fat: 'FAMS',+        niacin: 'NIA',+        phosphorus: 'P',+        polyunsaturated_fat: 'FAPU',+        potassium: 'K',+        protein: 'PROCNT',+        riboflavin: 'RIBF',+        saturated_fat: 'FASAT',+        sodium: 'NA',+        sugar: 'SUGAR',+        thiamin: 'THIA',+        trans_fat: 'FATRN',+        vitamin_a: 'VITA_RAE',+        vitamin_b6: 'VITB6A',+        vitamin_b12: 'VITB12',+        vitamin_c: 'VITC',+        vitamin_d: 'VITD',+        vitamin_e: 'TOCPHA',+        vitamin_k: 'VITK1',+        zinc: 'ZN'+      }+    end++    def send_request(body: nil, headers: {}, method:, name: nil, url:)+      ActiveSupport::JSON.decode(+        RestClient::Request.execute(+          headers: headers,+          method: method,+          payload: body,+          url: "#{url}#{url.include?('?') ? '&' : '?'}app_id=#{APP_ID}&app_key=#{APP_KEY}"

Use the URI module to parse and generate the URL.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class AddInitialData < ActiveRecord::Migration[6.0]+  def up+    ApplicationRecord.connection.execute(<<~SQL)+      INSERT INTO health_labels+      (created_at, id, name, updated_at)+      VALUES+      (CURRENT_TIMESTAMP, 1, 'Dairy-Free', CURRENT_TIMESTAMP),

indent

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_URL = 'https://api.edamam.com/api/food-database/nutrients'.freeze+  UPC_LOOKUP_URL = 'https://api.edamam.com/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement_name:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: "#{MEASUREMENT_URI_PREFIX}#{measurement_name.parameterize.underscore}",

Let's add a measurement_uri method that takes in the name and returns the full encoded URL.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+module Edamam+  APP_ID = ENV.fetch('EDAMAM_APP_ID')+  APP_KEY = ENV.fetch('EDAMAM_APP_KEY')+  MEASUREMENT_URI_PREFIX = 'http://www.edamam.com/ontologies/edamam.owl#Measure_'.freeze+  NUTRITION_DATA_URL = 'https://api.edamam.com/api/food-database/nutrients'.freeze+  UPC_LOOKUP_URL = 'https://api.edamam.com/api/food-database/parser'.freeze++  class << self+    def get_grams_per_measurement_unit(food_id:, measurement_name:)+      data = send_request(+        body: {+          ingredients: [+            {+              quantity: 1,+              measureURI: "#{MEASUREMENT_URI_PREFIX}#{measurement_name.parameterize.underscore}",+              foodId: food_id+            }+          ]+        }.to_json,+        headers: { 'Content-Type': 'application/json' },+        method: :post,+        name: 'measurement data',+        url: NUTRITION_DATA_URL+      )+      get_weight_from_nutrition_data_response(data)+    end++    def get_nutrition_data_from_upc(upc)+      upc_lookup_data = send_request(method: :get, name: 'UPC lookup', url: "#{UPC_LOOKUP_URL}?upc=#{upc}")+        &.dig('hints')+        &.first++      return unless upc_lookup_data&.is_a?(Hash)++      food_data = upc_lookup_data['food']+      return unless food_data&.is_a?(Hash)++      food_id = food_data['foodId']+      name = food_data['label']+      return unless food_id && name++      measurement_data = upc_lookup_data['measures']+      measurement_units =+        if measurement_data&.is_a?(Array)+          measurement_data.map { |measure| measure['label'] if measure&.is_a?(Hash) }.compact+        else+          []+        end++      body = {+        ingredients: [+          {+            quantity: 1,+            measureURI: "#{MEASUREMENT_URI_PREFIX}tablespoon",+            foodId: food_id+          }+        ]+      }+      request_data = {+        body: body.to_json,+        headers: { 'Content-Type': 'application/json' },+        method: :post,+        name: 'nutrition data',+        url: NUTRITION_DATA_URL+      }+      response = send_request(request_data)++      grams_per_tablespoon = get_weight_from_nutrition_data_response(response)+      unless grams_per_tablespoon+        body[:ingredients].first[:measureURI] = "#{MEASUREMENT_URI_PREFIX}gram"+        request_data[:body] = body.to_json+        response = send_request(request_data)+      end++      nutrients = response['totalNutrients']+      return unless nutrients++      divisor = grams_per_tablespoon || 1+      nutrients_data = nutrient_mappings.map do |nutrient, code|+        nutrient_data = nutrients[code]+        value =+          if nutrient_data+            case nutrient_data['unit']+            when 'g'+              cast_decimal(nutrient_data['quantity']) / divisor+            when 'mg'+              cast_decimal(nutrient_data['quantity']) / divisor * 1_000+            when 'µg'+              cast_decimal(nutrient_data['quantity']) / divisor * 1_000_000+            else+              nil+            end+          end++        [nutrient, value]+      end.to_h.merge(calories: cast_decimal(nutrients.dig('ENERC_KCAL', 'quantity')))++      {+        food_id: food_id,+        grams_per_tablespoon: grams_per_tablespoon,+        health_labels: response['healthLabels'],+        measurement_units: measurement_units,+        name: name,+        nutrients: nutrients_data+      }+    end++    private++    def cast_decimal(value)+      Kernel.Float(value).to_d+    rescue ArgumentError, TypeError+      nil+    end++    def get_weight_from_nutrition_data_response(data)+      return unless data&.is_a?(Hash)++      data = data['ingredients']+      return unless data&.is_a?(Array)++      data = data.first+      return unless data&.is_a?(Hash)++      data = data['parsed']+      return unless data&.is_a?(Array)++      data = data.first+      return unless data&.is_a?(Hash)++      data['weight'] unless data['status'] == 'MISSING_QUANTITY'

🤯 How could Mr. I-love-dig write such a method⁉️

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class AddInitialData < ActiveRecord::Migration[6.0]+  def up+    ApplicationRecord.connection.execute(<<~SQL)+      INSERT INTO health_labels+      (created_at, id, name, updated_at)

indent

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:items) do |table|+      table.decimal(:added_sugar)+      table.decimal(:calcium)+      table.decimal(:calories)+      table.decimal(:carbs)+      table.decimal(:cholesterol)+      table.decimal(:fat)+      table.decimal(:fiber)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron)+      table.decimal(:magnesium)+      table.decimal(:monounsaturated_fat)+      table.string(:name, null: false)+      table.decimal(:niacin)+      table.decimal(:phosphorus)+      table.decimal(:polyunsaturated_fat)+      table.decimal(:potassium)+      table.decimal(:protein)+      table.decimal(:riboflavin)+      table.decimal(:saturated_fat)+      table.decimal(:sodium)+      table.decimal(:sugar)+      table.decimal(:thiamin)+      table.decimal(:trans_fat)+      table.string(:upc)+      table.decimal(:vitamin_a)+      table.decimal(:vitamin_b6)+      table.decimal(:vitamin_b12)+      table.decimal(:vitamin_c)+      table.decimal(:vitamin_d)+      table.decimal(:vitamin_e)+      table.decimal(:vitamin_k)+      table.decimal(:zinc)+      table.timestamps+      table.index(%i[upc], unique: true)+    end++    create_table(:measurement_units) do |table|+      table.string(:name, null: false)+      table.timestamps+    end++    create_table(:item_measurement_units) do |table|+      table.integer(:grams, null: false)+      table.string(:item_id, null: false)+      table.bigint(:measurement_unit_id, null: false)+      table.timestamps+      table.index(+        %i[item_id measurement_unit_id],+        name: 'ix_item_measurement_units_on_item_id_and_measurement_unit_id',+        unique: true+      )+    end++    add_foreign_key(:item_measurement_units, :items)+    add_foreign_key(:item_measurement_units, :measurement_units)++    create_table(:health_labels) do |table|+      table.string(:name, null: false)+      table.timestamps+    end++    create_table(:item_health_labels) do |table|+      table.bigint(:health_label_id, null: false)+      table.bigint(:item_id, null: false)+      table.timestamps+      table.index(%i[health_label_id item_id], unique: true)

When would we use this index?

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:items) do |table|+      table.decimal(:added_sugar)+      table.decimal(:calcium)+      table.decimal(:calories)+      table.decimal(:carbs)+      table.decimal(:cholesterol)+      table.decimal(:fat)+      table.decimal(:fiber)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron)+      table.decimal(:magnesium)+      table.decimal(:monounsaturated_fat)+      table.string(:name, null: false)+      table.decimal(:niacin)+      table.decimal(:phosphorus)+      table.decimal(:polyunsaturated_fat)+      table.decimal(:potassium)+      table.decimal(:protein)+      table.decimal(:riboflavin)+      table.decimal(:saturated_fat)+      table.decimal(:sodium)+      table.decimal(:sugar)+      table.decimal(:thiamin)+      table.decimal(:trans_fat)+      table.string(:upc)+      table.decimal(:vitamin_a)+      table.decimal(:vitamin_b6)+      table.decimal(:vitamin_b12)+      table.decimal(:vitamin_c)+      table.decimal(:vitamin_d)+      table.decimal(:vitamin_e)+      table.decimal(:vitamin_k)+      table.decimal(:zinc)+      table.timestamps+      table.index(%i[upc], unique: true)+    end++    create_table(:measurement_units) do |table|+      table.string(:name, null: false)+      table.timestamps

Add a regular index on name.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:items) do |table|+      table.decimal(:added_sugar)+      table.decimal(:calcium)+      table.decimal(:calories)+      table.decimal(:carbs)+      table.decimal(:cholesterol)+      table.decimal(:fat)+      table.decimal(:fiber)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron)+      table.decimal(:magnesium)+      table.decimal(:monounsaturated_fat)+      table.string(:name, null: false)+      table.decimal(:niacin)+      table.decimal(:phosphorus)+      table.decimal(:polyunsaturated_fat)+      table.decimal(:potassium)+      table.decimal(:protein)+      table.decimal(:riboflavin)+      table.decimal(:saturated_fat)+      table.decimal(:sodium)+      table.decimal(:sugar)+      table.decimal(:thiamin)+      table.decimal(:trans_fat)+      table.string(:upc)+      table.decimal(:vitamin_a)+      table.decimal(:vitamin_b6)+      table.decimal(:vitamin_b12)+      table.decimal(:vitamin_c)+      table.decimal(:vitamin_d)+      table.decimal(:vitamin_e)+      table.decimal(:vitamin_k)+      table.decimal(:zinc)+      table.timestamps+      table.index(%i[upc], unique: true)

We should probably have a fulltext index on name as well.

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class ItemService+  class << self+    def create_item_from_upc(upc)+      data = Edamam.get_nutrition_data_from_upc(upc)+      return unless data++      health_label_ids = HealthLabel+        .ids+        .values_at(*data[:health_labels].map { |health_label| health_label.downcase.to_sym })+        .compact++      custom_measurement_unit_names = data[:measurement_units] - MeasurementUnit.standard.keys+      custom_measurement_units = MeasurementUnit.where(name: custom_measurement_unit_names).to_a

Why not MeasurementUnit.custom to match standard?

tommy-russoniello

comment created time in 2 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class ItemMeasurementUnit < ApplicationRecord+  belongs_to :item+  belongs_to :measurement_unit++  validates :grams, presence: true

positive number

tommy-russoniello

comment created time in 3 months

issue closedcerebris/jsonapi-resources

Include all fields of relationship

This issue is a (choose one):

  • [x] Problem/bug report.
  • [ ] Feature request.
  • [ ] Request for support. Note: Please try to avoid submitting issues for support requests. Use Gitter instead.

Checklist before submitting:

  • [x] I've searched for an existing issue.
  • [ ] I've asked my question on Gitter and have not received a satisfactory answer.
  • [ ] I've included a complete bug report template. This step helps us and allows us to see the bug without trying to reproduce the problem from your description. It helps you because you will frequently detect if it's a problem specific to your project.
  • [ ] The feature I'm asking for is compliant with the JSON:API spec.

Description

I have

 class PostResource < JSONAPI::Resource
   attributes :title, :content, :published
    has_many :comments, always_include_linkage_data: true
  end

class CommentResource < JSONAPI::Resource
   attributes :content, :post_id
     belongs_to :post, optional: true
   end

How to include comments all fields? I can include it via /posts?include=comments But this, include comments separately in response 'include' field

Is it possible to include it directly in post relationships?


"relationships": {
"comments": {
"data": [
{
"type": "comments",
"id": "1",
 # here I want comment content
}
}

}

closed time in 3 months

rusikf

issue commentcerebris/jsonapi-resources

Include all fields of relationship

What you're asking for does not comply with JSON-API. See https://jsonapi.org/format/#fetching-includes

rusikf

comment created time in 3 months

CommitCommentEvent
CommitCommentEvent
CommitCommentEvent
CommitCommentEvent
CommitCommentEvent
CommitCommentEvent
CommitCommentEvent

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class Item < ApplicationRecord+  belongs_to :brand+  belongs_to :item_family+  belongs_to :variety++  validates :added_sugar, numericality: { greater_than_or_equal_to: 0 }, presence: true

None of these nutrient values should be required. This would make it either extremely annoying to manually add an item or we'd end up with really bad data.

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:item_families) do |table|+      table.bigint(:item_family_id)+      table.string(:name, null: false)+      table.timestamps+      table.index(%i[item_family_id])+      table.index(%i[name], unique: true)+    end++    add_foreign_key(:item_families, :item_families)++    create_table(:varieties) do |table|+      table.string(:name, null: false)+      table.timestamps+      table.index(%i[name], unique: true)+    end++    create_table(:brands) do |table|+      table.string(:name, null: false)+      table.timestamps+      table.index(%i[name], unique: true)+    end++    create_table(:items) do |table|+      table.decimal(:added_sugar, null: false)+      table.bigint(:brand_id)+      table.decimal(:calcium, null: false)+      table.decimal(:calories, null: false)+      table.decimal(:carbs, null: false)+      table.decimal(:cholesterol, null: false)+      table.decimal(:fat, null: false)+      table.decimal(:fiber, null: false)+      table.decimal(:folate, null: false)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron, null: false)+      table.bigint(:item_family_id)+      table.decimal(:magnesium, null: false)+      table.decimal(:monounsaturated_fat, null: false)+      table.string(:name, null: false)+      table.decimal(:niacin, null: false)+      table.decimal(:phosphorus, null: false)+      table.decimal(:polyunsaturated_fat, null: false)+      table.decimal(:potassium, null: false)+      table.decimal(:protein, null: false)+      table.decimal(:riboflavin, null: false)+      table.decimal(:saturated_fat, null: false)+      table.decimal(:sodium, null: false)+      table.decimal(:sugar, null: false)+      table.decimal(:thiamin, null: false)+      table.decimal(:trans_fat, null: false)+      table.bigint(:variety_id)+      table.decimal(:vitamin_a, null: false)+      table.decimal(:vitamin_b6, null: false)+      table.decimal(:vitamin_b12, null: false)+      table.decimal(:vitamin_c, null: false)+      table.decimal(:vitamin_d, null: false)+      table.decimal(:vitamin_e, null: false)+      table.decimal(:vitamin_k, null: false)+      table.timestamps+      table.index(%i[brand_id])+      table.index(%i[item_family_id variety_id brand_id], unique: true)+      table.index(%i[variety_id])+    end++    add_foreign_key(:items, :brands)+    add_foreign_key(:items, :item_families)+    add_foreign_key(:items, :varieties)++    create_table(:quantity_units) do |table|+      table.string(:name, null: false)+      ###type?+      table.timestamps+      table.index(%i[name type??], unique: true)

.

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class Item < ApplicationRecord+  belongs_to :brand+  belongs_to :item_family

How are families going to work?

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class QuantityUnit < ApplicationRecord

This should be named MeasurementUnit.

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class CreateInitialEntities < ActiveRecord::Migration[6.0]+  def change+    create_table(:item_families) do |table|+      table.bigint(:item_family_id)+      table.string(:name, null: false)+      table.timestamps+      table.index(%i[item_family_id])+      table.index(%i[name], unique: true)+    end++    add_foreign_key(:item_families, :item_families)++    create_table(:varieties) do |table|+      table.string(:name, null: false)+      table.timestamps+      table.index(%i[name], unique: true)+    end++    create_table(:brands) do |table|+      table.string(:name, null: false)+      table.timestamps+      table.index(%i[name], unique: true)+    end++    create_table(:items) do |table|+      table.decimal(:added_sugar, null: false)+      table.bigint(:brand_id)+      table.decimal(:calcium, null: false)+      table.decimal(:calories, null: false)+      table.decimal(:carbs, null: false)+      table.decimal(:cholesterol, null: false)+      table.decimal(:fat, null: false)+      table.decimal(:fiber, null: false)+      table.decimal(:folate, null: false)+      table.decimal(:grams_per_tablespoon)+      table.decimal(:iron, null: false)+      table.bigint(:item_family_id)+      table.decimal(:magnesium, null: false)+      table.decimal(:monounsaturated_fat, null: false)+      table.string(:name, null: false)+      table.decimal(:niacin, null: false)+      table.decimal(:phosphorus, null: false)+      table.decimal(:polyunsaturated_fat, null: false)+      table.decimal(:potassium, null: false)+      table.decimal(:protein, null: false)+      table.decimal(:riboflavin, null: false)+      table.decimal(:saturated_fat, null: false)+      table.decimal(:sodium, null: false)+      table.decimal(:sugar, null: false)+      table.decimal(:thiamin, null: false)+      table.decimal(:trans_fat, null: false)+      table.bigint(:variety_id)+      table.decimal(:vitamin_a, null: false)+      table.decimal(:vitamin_b6, null: false)+      table.decimal(:vitamin_b12, null: false)+      table.decimal(:vitamin_c, null: false)+      table.decimal(:vitamin_d, null: false)+      table.decimal(:vitamin_e, null: false)+      table.decimal(:vitamin_k, null: false)+      table.timestamps+      table.index(%i[brand_id])+      table.index(%i[item_family_id variety_id brand_id], unique: true)+      table.index(%i[variety_id])+    end++    add_foreign_key(:items, :brands)+    add_foreign_key(:items, :item_families)+    add_foreign_key(:items, :varieties)++    create_table(:quantity_units) do |table|+      table.string(:name, null: false)+      ###type?

I don't think type will be needed. We're going to have to hardcode the standard units anyway.

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class Item < ApplicationRecord+  belongs_to :brand+  belongs_to :item_family+  belongs_to :variety

Why do we care about variety as an entity?

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class ItemQuantityUnit < ApplicationRecord

The class and file name do not match.

tommy-russoniello

comment created time in 3 months

Pull request review commenttommy-russoniello/pantry-buddy

[WIP] Add initial entities

+class Brand < ApplicationRecord

Why do we care about brands as their own entities?

tommy-russoniello

comment created time in 3 months

issue commentscottgonzalez/node-browserstack

Feature request: Add support for the App Automate API

Just published v1.6.0.

decates

comment created time in 3 months

pull request commentscottgonzalez/node-browserstack

Add AppAutomateClient

Just published v1.6.0.

b1zzu

comment created time in 3 months

pull request commentscottgonzalez/node-browserstack

Updated readme for app automate

Just published v1.6.0.

satyasreem

comment created time in 3 months

created tagscottgonzalez/node-browserstack

tagv1.6.0

node.js client for BrowserStack

created time in 3 months

push eventscottgonzalez/node-browserstack

Scott González

commit sha 40f9f9c50dc5798b80747eae8cb6b67f244ffc27

1.6.0

view details

push time in 3 months

push eventscottgonzalez/node-browserstack

Scott González

commit sha 5e634fc536af82f1630db5990e029b43e1b1ab8b

README: Add docs for App Automate client

view details

smuralidharan

commit sha 0805be1661107b2e4a7009f4dd663b3b46322252

README: Add example for App Automate Closes gh-67

view details

Scott González

commit sha eb138940a6d04878f00f95cc97ea46572f7c39cd

Update license

view details

Scott González

commit sha 4bc7ec7ebd8df80fdcaedafd924c6b6255378b03

Build: Add package-lock.json

view details

push time in 3 months

PR closed scottgonzalez/node-browserstack

Updated readme for app automate

-- README update for app automate. -- getBrowsers is not available for App Automate. Using getBuilds as an example

+9 -0

0 comment

1 changed file

satyasreem

pr closed time in 3 months

pull request commentscottgonzalez/node-browserstack

Add AppAutomateClient

@satyasreem Yes, I thought @b1zzu was going to publish it after merging, but I will take care of this. I would like to have the README updated to show the App Automate API though. If there's no PR for that by the time I go to publish this (probably tonight), I'll write up the docs myself.

b1zzu

comment created time in 3 months

issue closedscottgonzalez/node-browserstack

Feature request: Add support for the App Automate API

It looks very similar to the automate API, but uses a different base URL.

Docs: Automate API App Automate API

closed time in 3 months

decates

pull request commentscottgonzalez/sane-email-validation

Allow international addresses

Thanks. This is now on npm as v3.0.1.

v3.0.0 was released as well, but had a typo in the README.

thusoy

comment created time in 3 months

created tagscottgonzalez/sane-email-validation

tagv3.0.1

Sanely validate email addresses, based on HTML5's definition of email addresses

created time in 3 months

push eventscottgonzalez/sane-email-validation

Scott González

commit sha 4dbe7ee14ada16fee044368f36934a7a243732d6

README: Fix typo

view details

Scott González

commit sha 8bab45c850bbb4acbd3b5b6ca57359a2e00ce46e

3.0.1

view details

push time in 3 months

created tagscottgonzalez/sane-email-validation

tagv3.0.0

Sanely validate email addresses, based on HTML5's definition of email addresses

created time in 3 months

push eventscottgonzalez/sane-email-validation

Tarjei Husøy

commit sha 161cd87c144310b0324bb35d2d04439d43570e15

Allow Unicode Add `isAsciiEmail` and `isNotAsciiEmail` to mimic old functionality. Closes gh-3

view details

Scott González

commit sha 0a4bd38ca810546f3918f9ab62657c6c7a46c573

Update README for new methods

view details

Scott González

commit sha 8c402cd876d818a77461c2cfe3934f6bf35a51b7

Update copyright information

view details

Scott González

commit sha 626cdd5bd8d95b1ec8f62d2f72e7f77bf6e764d6

Update dependencies

view details

Scott González

commit sha 2ad7e9a5f6ad6b937b1eda7e84fcf7ed283724b4

3.0.0

view details

push time in 3 months

PR closed scottgonzalez/sane-email-validation

Allow international addresses

International email addresses are becoming more and more popular, validators shouldn't prevent that. In addition to the unit tests I've also verified this works with all the example emails from the wikipedia article.

+204 -22

5 comments

2 changed files

thusoy

pr closed time in 3 months

Pull request review commentscottgonzalez/sane-email-validation

Allow international addresses

 exports = module.exports = isEmail

I know this isn't much shorter, but it does remove the duplication. What do you think?

// Unicode ranges from RFC 3987
//    ucschar        = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
//       / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
//       / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
//       / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
//       / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
//       / %xD0000-DFFFD / %xE1000-EFFFD
const unicodeRanges = [
  '\u00A0-\uD7FF',
  '\uF900-\uFDCF',
  '\uFDF0-\uFFEF',
  '\u10000-\u1FFFD',
  '\u20000-\u2FFFD',
  '\u30000-\u3FFFD',
  '\u40000-\u4FFFD',
  '\u50000-\u5FFFD',
  '\u60000-\u6FFFD',
  '\u70000-\u7FFFD',
  '\u80000-\u8FFFD',
  '\u90000-\u9FFFD',
  '\uA0000-\uAFFFD',
  '\uB0000-\uBFFFD',
  '\uC0000-\uCFFFD',
  '\uD0000-\uDFFFD',
  '\uE1000-\uEFFFD'
].join('')

const methods = [
  {
    name: 'isEmail',
    characters: unicodeRanges,
    test: () => true
  },
  {
    name: 'isAsciiEmail',
    characters: '',
    test: (parts) => {
      const labels = parts[1].split('.')
      for (const label of labels) {
        if (label.indexOf('xn--') === 0) {
          return false
        }
      }

      return true
    }
  }
].reduce((methods, { characters, name, test }) => {
  const localAddr = new RegExp(`^[a-z0-9.!#$%&'*+/=?^_\`{|}~${characters}-]+$`, 'i')
  const label = `[a-z0-9${characters}](?:[a-z0-9${characters}-]{0,61}[a-z0-9${characters}])?`
  const domain = new RegExp(`^${label}(?:\\.${label})+$`, 'i')

  methods[name] = (string) => {
    const parts = string.split('@')

    if (parts.length !== 2) {
      return false
    }

    if (!localAddr.test(parts[0])) {
      return false
    }

    if (!domain.test(parts[1])) {
      return false
    }

    if (parts[ 0 ].substr(-1) === '.') {
      return false
    }

    return test(parts)
  }

  return methods
}, {})

exports = module.exports = methods.isEmail
exports.isAsciiEmail = methods.isAsciiEmail

exports.isNotEmail = (string) => {
  return !methods.isEmail(string)
}

exports.isNotAsciiEmail = (string) => {
  return !methods.isAsciiEmail(string)
}
thusoy

comment created time in 3 months

PullRequestEvent

pull request commentscottgonzalez/sane-email-validation

Allow international addresses

How about we expose a third method isUnicodeEmail (or similar name)? Or perhaps even change the existing one to isAsciiEmail.

thusoy

comment created time in 3 months

PR closed scottgonzalez/sane-email-validation

Allow international addresses

International email addresses are becoming more and more popular, validators shouldn't prevent that. In addition to the unit tests I've also verified this works with all the example emails from the wikipedia article.

+47 -4

1 comment

2 changed files

thusoy

pr closed time in 3 months

pull request commentscottgonzalez/sane-email-validation

Allow international addresses

In the real world, internationalization doesn’t work so well, and therefore does not meet the criteria of being sane. The Wikipedia article you linked to even mentions that the UTF-8 encoded addresses have support issues.

There first email validation I wrote fully supported internationalization, along with many other spec-valid rules that just don’t make sense in the real world using real (old) infrastructure to support the Internet. That’s why I created this module to reflect reality.

thusoy

comment created time in 3 months

more