wrapping code that runs in Rails environment into a module - ruby-on-rails

I have this code and it works perfectly
require "date"
#past = []
#future = []
#artist = Artist.find(2)
def sort_by_date(artist)
artist.events.each do |event|
if event.date < DateTime.now
#past << event.id
else
#future << event.id
end
end
end
def event_title(arr)
arr.each do |event_id|
e = Event.find(event_id)
artist_names = []
e.artists.each do |artist|
unless artist.name == #artist.name
artist_names << artist.name
end
end
puts "#{e.name} with #{artist_names.join(", ")} at #{(Venue.find(e.venue_id)).name}"
end
end
sort_by_date(#artist)
puts "Upcoming Events: "
event_title(#future)
puts "Past Events: "
event_title(#past)
I want to run wrap this operation into a module, but I'm having trouble understanding how to pass artist_id to it properly. With this command rails runner app/modules/artist_event_sort.rb, I'm getting this error: ``': undefined method sort_by_date' for SortedArtistEvents:Module (NoMethodError). The two methods sort_by_date and event_title worked as they should before I tried wrapping this whole operation up into a module, so that's where I know I've missed something.
module SortedArtistEvents
require "date"
attr_accessor :artist_id
def initialize(artist_id)
#past = []
#future = []
#artist = Artist.find(artist_id)
end
def sort_by_date(artist)
artist.events.each do |event|
if event.date < DateTime.now
#past << event.id
else
#future << event.id
end
end
end
def event_title(arr)
arr.each do |event_id|
e = Event.find(event_id)
artist_names = []
e.artists.each do |artist|
unless artist.name == #artist.name
artist_names << artist.name
end
end
puts "#{e.name} with #{artist_names.join(", ")} at #{(Venue.find(e.venue_id)).name}"
end
end
sort_by_date(#artist)
puts "Upcoming Events: "
self.event_title(#future)
puts "Past Events: "
event_title(#past)
end
class LetsSort
include SortedArtistEvents
end
test_artist_sort = LetsSort.new(2)

It looks like there are a couple things wrong here. You are trying to initialize a module, you can only initialize a class, e.g. class SortedArtistEvents.
If you have this:
module Foo
def bar; end
end
bar is only accessible by including or extending a module or class with Foo. With your error undefined method sort_by_date' for SortedArtistEvents:Module you would have to do
module SortedArtistsEvents
def self.sort_by_date; end
end
to get behavior like SortedArtistsEvents.sort_by_date

Related

Ruby on rails method partials?

I was wondering if it is possible to create a method partial in ruby on rails, for example I have this code;-
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [#slots.slot_one, #slots.slot_two, #slots.slot_three, #slots.slot_four, #slots.slot_five,
#slots.slot_six, #slots.slot_seven, #slots.slot_eight, #slots.slot_nine, #slots.slot_ten]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
Written in multiple methods to get the #user_products, I was wondering if there was a way so I don't have to write this all the time and possibly run a method or use a partial?
Would it be worth creating a helper that does this and returns the #user_products variable?
I took my own advice and created two helpers, one to return the #user_products and another to return the #total.
I added the names of the methods to our helper_method
helper_method :user_is_admin?, :authenticate_admin!, :product_available?, :get_user_products!, :get_user_total!
then added these two methods at the bottom of the file;-
get_user_products!
def get_user_products!
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [#slots.slot_one, #slots.slot_two, #slots.slot_three, #slots.slot_four, #slots.slot_five,
#slots.slot_six, #slots.slot_seven, #slots.slot_eight, #slots.slot_nine, #slots.slot_ten]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
return #user_products
end
get_user_total!
def get_user_total!
#total = 0
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [#slots.slot_one, #slots.slot_two, #slots.slot_three, #slots.slot_four, #slots.slot_five,
#slots.slot_six, #slots.slot_seven, #slots.slot_eight, #slots.slot_nine, #slots.slot_ten]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
#user_products.each do |p|
#total += p.product_price
end
return #total
end
To use these methods inside whatever controller you then do the following;-
#user_products = get_user_products!
#total = get_user_total!
I assume this is in a controller?
What you want is to use plain old Ruby objects (POROs). So, you might have something like this:
class UserProducts
class << self
def get(options={})
#cart = Cart.where(:user_id => current_user.id).first if user_signed_in?
#slots = #cart.slots.first
#slot_list = [
#slots.slot_one,
#slots.slot_two,
#slots.slot_three,
#slots.slot_four,
#slots.slot_five,
#slots.slot_six,
#slots.slot_seven,
#slots.slot_eight,
#slots.slot_nine,
#slots.slot_ten
]
#user_products = []
#product = []
#slot_list.each do |item|
if item.nil?
p 'Item empty'
else
#product << item
end
end
#product.each do |item|
items = Product.where(:product_id => item).first
#user_products << items
end
end
end
Then, in your controller, you'd do something like:
class FooController < ApplicationController
def index
UserProducts.get(user_id: current_user.id)
end
end
So, UserProducts is essentially a service object. I think some people call them use cases. I tend to call them 'managers'. I put them in their own directory as app/managers/user_products.rb.

Undefined Method in Rails even though the method exist

I have a method in my view helper directory that I am trying to use within a model but i keep getting a undefined method error. I cannot figure out what i am doing wrong.This is my module.
module StbHelper
def gen_csv(stbs)
CSV.generate do |csv|
csv << [
'param1',
'param2'
]
stbs.each do |stb|
health_check = stb.stb_health_checks.last
csv << [
'value1',
'value2'
]
end
end
end
This is the class i want to use the method in.
require 'stb_helper'
class Stb < ActiveRecord::Base
def self.get_notes_data
.
.
.
end
def self.update
.
.
.
end
def self.report(options={})
csv_file = nil
if options == {}
########################################
# This is the line that throws the error
csv_file = StbHelper.gen_csv(Stb.all)
#######################################
else
stbs = []
customers = List.where(id: options[:list])[0].customers
customers.each do |customer|
customer.accounts.each do |account|
stbs += account.stbs
end
end
csv_file = StbHelper.gen_csv(stbs)
end
end
end
You've defined a module, that doesn't require instantiation. You should be able to use it without the StbHelper part (as long as you require the module in the document):
def self.report(options={})
csv_file = nil
if options == {}
########################################
# This is the line that throws the error
csv_file = gen_csv(Stb.all)
#######################################
else
stbs = []
customers = List.where(id: options[:list])[0].customers
customers.each do |customer|
customer.accounts.each do |account|
stbs += account.stbs
end
end
csv_file = gen_csv(stbs)
end
end
But you shouldn't use a helper for this, you can create a normal module and require it the same way.
Edit: Save the module in a new folder called app/modules (and restart the server), save a file called stb_helper.rb with the contents of your module:
module StbHelper
def gen_csv(stbs)
CSV.generate do |csv|
csv << [
'param1',
'param2'
]
stbs.each do |stb|
health_check = stb.stb_health_checks.last
csv << [
'value1',
'value2'
]
end
end
end

Check if Form input was empty

I have the following parameters
def note_params
params.require(:note).permit(
:content
)
end
Now i am trying to check of the content was empty for :content i am passing this to a service object
def add_note_to_plan
unless #note_params.content.empty?
puts "======================================================"
note = Note.new(
note_params.merge(
plan: #plan,
user: #current_user
)
)
note.save
end
puts "=================== outside ==================================="
end
Service Object
class PlanCreator
def initialize(current_user, venue_params, plan_params, note_params)
#current_user = current_user
#venue_params = venue_params
#plan_params = plan_params
#note_params = note_params
end
attr_reader :venue, :plan
def create
#venue = new_or_existing_venue
#plan = new_or_existing_plan
save_venue && save_plan && add_current_user_to_plan && add_note_to_plan
end
def errors
{
venue: venue_errors,
plan: plan_errors,
note: note_errors
}
end
private
attr_reader :current_user, :venue_params, :plan_params, :note_params
..... Removed all the unnecessary methods
def add_note_to_plan
unless #note_params.content.empty?
puts "======================================================"
note = Note.new(
note_params.merge(
plan: #plan,
user: #current_user
)
)
note.save
end
puts "=================== outside ==================================="
end
end
Error:
NoMethodError - undefined method `content' for
{"content"=>""}:ActionController::Parameters:
Change this:
unless #note_params.content.empty?
To this:
unless #note_params[:content].empty?
ActionController's params returns a hash of parameters.

Ruby: NoMethodError: undefined method `<<' for nil:NilClass

I get the error "NoMethodError: undefined method `<<' for nil:NilClass" when trying to add an object to an empty array. I think it relates to the array being nil instead of empty, and it's not allowing me to append a new object.
The problem occurs with the last line cashier.rule_set.add(apple_rule). Not sure if I am implementing the RuleSet class and initializing #rules correctly.
class Rule
attr_reader :sku, :quantity, :price
def initialize(sku, quantity, price)
#sku = sku
#quantity = quantity
#price = price
end
end
class RuleSet
attr_accessor :rules
def initalize()
#rules = []
end
def add(rule)
#rules << rule
end
def rule_for_sku(sku)
#rules.detect { |r| r.sku == sku }
end
end
class Product
attr_accessor :name, :price, :sku
def initialize(name, price)
puts "Added #{name}, which costs $#{price} to available inventory."
#name = name
#price = price
#sku = (rand(100000) + 10000).to_s
end
end
class Cashier
attr_accessor :rule_set
def initialize
#cart = []
#total_cost = 0
#rule_set = RuleSet.new
end
def add_to_cart(product)
puts "Added #{product.name} to your cart."
#cart << product
end
def in_cart
#cart.each_with_object(Hash.new(0)) {|item, counts| counts[item] += 1}
end
def checkout
self.in_cart.each do |item, quantity|
rule = self.rule_set.rule_for_sku(item.sku)
if rule.present? && quantity >= rule.quantity
total_cost += item.price
end
end
end
end
##Testing
#Initialize list of available products and costs
apple = Product.new("apple", 5)
banana = Product.new("banana", 2)
grape = Product.new("grape", 3)
apple_rule = Rule.new(apple.sku, 3, 12)
cashier = Cashier.new
cashier.rule_set.add(apple_rule)
You have misspelt initialize in your RuleSet class (initalize) so that method isn't being called and #rules is not being set to an empty array.

Creating Message Object Parser

I'm receiving results from a web service like this:
result.body returns:
[2] pry(#<User::EmailSettingsController>)> result.body
=> {"RESULT"=>
{"MESSAGES"=>
[{"MESSAGE"=>
{"TYPE"=>"E",
"ID"=>"HRRCF_WD_UI",
"NUMBER"=>"025",
"MESSAGE"=>"U kunt maximaal \"5\" jobagents creëren 1",
"LOG_NO"=>"",
"LOG_MSG_NO"=>"000000",
"MESSAGE_V1"=>"5",
"MESSAGE_V2"=>"1",
"MESSAGE_V3"=>"",
"MESSAGE_V4"=>"",
"PARAMETER"=>"",
"ROW"=>"0",
"FIELD"=>"",
"SYSTEM"=>""}},
{"MESSAGE"=>
{"TYPE"=>"E",
"ID"=>"HRRCF_WD_UI",
"NUMBER"=>"025",
"MESSAGE"=>"U kunt maximaal \"5\" jobagents creëren 2",
"LOG_NO"=>"",
"LOG_MSG_NO"=>"000000",
"MESSAGE_V1"=>"5",
"MESSAGE_V2"=>"2",
"MESSAGE_V3"=>"",
"MESSAGE_V4"=>"",
"PARAMETER"=>"",
"ROW"=>"0",
"FIELD"=>"",
"SYSTEM"=>""}},
{"MESSAGE"=>
{"TYPE"=>"E",
"ID"=>"HRRCF_WD_UI",
"NUMBER"=>"025",
"MESSAGE"=>"U kunt maximaal \"5\" jobagents creëren 3",
"LOG_NO"=>"",
"LOG_MSG_NO"=>"000000",
"MESSAGE_V1"=>"5",
"MESSAGE_V2"=>"3",
"MESSAGE_V3"=>"",
"MESSAGE_V4"=>"",
"PARAMETER"=>"",
"ROW"=>"0",
"FIELD"=>"",
"SYSTEM"=>""}}]}}
Is it possible to create something ParseMessageObject(result.body) that returns that I can do something like this.
message_list = ParseMessageObject(result.body)
message_list.each do |message|
puts message.message
puts message.type
end
I have no idea if this is possible or how to do this any suggestions to get me started are welcome!
EDIT 1:
Created my class in lib:
class MessageParser
def self.parse(result)
end
end
This should basically do what you want, using a simple open struct to create a message class which has accessors for each of the keys in your message hash
require 'ostruct'
class MessageParser
Message = Struct.new(:type, :id, :number, :message, :log_no, :log_msg_no, :message_v1, :message_v2, :message_v3, :message_v4, :parameter, :row, :field, :system)
attr_reader :messages
def initialize(data)
#data = data.fetch("MESSAGES",[])
#messages = []
parse_data
end
private
def parse_data
#data.each do | msg |
message = Message.new
msg.fetch("MESSAGE",{}).each do |key, value|
message[key.downcase.to_sym] = value
end
#messages << message
end
end
end
parser = MessageParser.new(result.body["RESULT"])
parser.messages.each do |message|
puts message.message
puts message.type
end
Something like this should work:
class ParsedMessages
include Enumerable
attr_reader :messages
def initialize(data)
#messages = extract_messages_from_data(data)
end
def extract_messages_from_data(data)
# TODO: Parse data and return message objects
end
def each &block
#messages.each do |message|
if block_given?
block.call message
else
yield message
end
end
end
end
Now you can use all methods from Enumerable on ParsedMessages, like each, find, map etc etc.

Resources