How to pass argument into def_delegator - ruby

In order to return the correct roster for a store, I need to be able to pass the store_id argument into the delegator. Is this possible?
require "forwardable"
class Store
extend Forwardable
def_delegator :#roster, :names, :roster
attr_accessor :store_id
def initialize(store_id)
#store_id = store_id
#roster = Roster.new
end
end
class Roster
def names(store_id)
{
1 => ['Ned', 'Smith', 'Jerry', 'Ben'],
2 => ['Preeti', 'Jean', 'Sam', 'Lol']
}[store_id]
end
end
store = Store.new(1)
store.roster # => ['Ned', 'Smith', 'Jerry', 'Ben']

Related

Delete method in plain Ruby is not working

Please see below.
The delete method is not working and I do not know why.
I am trying to delete a customer without using rails and just plain ruby.
please can you help.
wrong number of arguments (given 0, expected 1) (ArgumentError)
from /Users/mustafaalomer/code/MustafaAlomer711/fullstack-challenges/02-OOP/05-Food-Delivery-Day-One/01-Food-Delivery/app/repositories/customer_repository.rb:28:in `delete'
from /Users/mustafaalomer/code/MustafaAlomer711/fullstack-challenges/02-OOP/05-Food-Delivery-Day-One/01-Food-Delivery/app/controllers/customers_controller.rb:33:in `destroy'
from /Users/mustafaalomer/code/MustafaAlomer711/fullstack-challenges/02-OOP/05-Food-Delivery-Day-One/01-Food-Delivery/router.rb:36:in `route_action'
from /Users/mustafaalomer/code/MustafaAlomer711/fullstack-challenges/02-OOP/05-Food-Delivery-Day-One/01-Food-Delivery/router.rb:13:in `run'
from app.rb:19:in `<main>'
require_relative "../views/customers_view"
require_relative "../models/customer"
class CustomersController
def initialize(customer_repository)
#customer_repository = customer_repository
#customers_view = CustomersView.new
end
def add
# ask user for a name
name = #customers_view.ask_user_for(:name)
# ask user for a address
address = #customers_view.ask_user_for(:address)
# make a new instance of a customer
customer = Customer.new(name: name, address: address)
# add the customer to the repository
#customer_repository.create(customer)
list
end
def list
customers = #customer_repository.all
#customers_view.display_list(customers)
end
def destroy
# ask user for the id to delete
list
id = #customers_view.ask_user_to_delete(:id)
# customer = #customer_repository.find(id)
# #customer_repository.delete(customer)
end
end
require 'csv'
require_relative '../models/customer'
class CustomerRepository
def initialize(csv_file)
#csv_file = csv_file
#customers = []
#next_id = 1
load_csv if File.exist?(csv_file)
end
def all
#customers
end
def create(customer)
customer.id = #next_id
#customers << customer
#next_id += 1
save_csv
end
def find(id)
#customers.find { |customer| customer.id == id}
end
def delete(id)
#customers.delete { |customer| customer.id == id}
end
private
def save_csv
CSV.open(#csv_file, "wb") do |csv|
csv << %w[id name address]
#customers.each do |customer|
csv << [customer.id, customer.name, customer.address]
end
end
end
def load_csv
CSV.foreach(#csv_file, headers: :first_row, header_converters: :symbol) do |row|
row[:id] = row[:id].to_i
#customers << Customer.new(row)
end
#next_id = #customers.last.id + 1 unless #customers.empty?
end
end
delete always takes an argument.
delete_if can be given a block and seems to be what you're looking for.

How to test "initialize" method using RSpec

github_asset.rb
# frozen_string_literal: true
require 'asset_ingester/helpers/project_details'
require 'active_model'
module AssetIngester
module Asset
class GithubAsset
include ActiveModel::Serializers::JSON
attr_reader :id, :name, :full_name, :description, :owner_name, :owner_url,
:owner_avatar_url, :url, :html_url, :artifact_id, :jiras, :asset_type
# Public: Initializes an instance of the GithubAsset class
#
# repo - A hash containing github repository details
# asset_type - A string representation of the asset type
def initialize(repo, asset_type)
#id = repo[:id]
#name = repo[:name]
#full_name = repo[:full_name]
#description = repo[:description]
#owner_name = repo.dig(:owner, :login)
#owner_url = repo.dig(:owner, :url)
#owner_avatar_url = repo.dig(:owner, :avatar_url)
#url = repo[:url]
#html_url = repo[:html_url]
#asset_type = asset_type
#artifact_id = repo[:artifact_id] if repo[:artifact_id] && !repo[:artifact_id].empty?
#jiras = repo[:jiras] if repo[:jiras] && !repo[:jiras].empty?
end
# Public: Defines the JSON serialization structure
#
# https://edgeguides.rubyonrails.org/active_model_basics.html#serialization
def attributes
{
'id' => #id,
'name' => #name,
'full_name' => #full_name,
'description' => #description,
'owner_name' => #owner_name,
'owner_url' => #owner_url,
'owner_avatar_url' => #owner_avatar_url,
'url' => #url,
'html_url' => #html_url,
'asset_type' => #asset_type,
'artifact_id' => #artifact_id,
'jiras' => #jiras
}.compact
end
end
end
end
github_asset_spec.rb
require 'asset_ingester/asset/github_asset'
RSpec.describe AssetIngester::Asset::GithubAsset, type: :api do
context "creating" do
let(:asset_type) {"node_package"}
let(:repo) do
[id: 131_690,
name: 'acm-care-management-js',
full_name: 'AcuteCaseManagementUI/acm-care-management-js',
owner_name: 'AcuteCaseManagementUI',
owner_url: 'https://github.cerner.com/api/v3/users/AcuteCaseManagementUI',
owner_avatar_url: 'https://avatars.github.cerner.com/u/4095?',
url: 'https://github.cerner.com/api/v3/repos/AcuteCaseManagementUI/acm-care-management-js',
html_url: 'https://github.cerner.com/AcuteCaseManagementUI/acm-care-management-js',
asset_type: 'node_package',
artifact_id: "",
jiras: [] ]
end
describe '::attributes' do
subject { AssetIngester::Asset::GithubAsset.attributes(repo, asset_type) }
it 'instantiates the class with 2 arguments' do
expect(subject).to be_an_instance_of(AssetIngester::Asset::GithubAsset)
end
it 'sets a to the first argument' do
expect(subject.repo).to eq(repo)
end
it 'sets b to the second argument' do
expect(subject.asset_type).to eq(asset_type)
end
end
end
end
This is how i tried testing the github_asset.rb file but however I'am receiving the following error while defining the subject
AssetIngester::Asset::GithubAsset creating ::attributes instantiates the class with 2 arguments
Failure/Error: subject { AssetIngester::Asset::GithubAsset.attributes(repo, asset_type) }
NoMethodError:
undefined method `attributes' for AssetIngester::Asset::GithubAsset:Class
Did you mean? attr_writer
I am green to RSpec testing and want to know how this can be done.
You get that NoMethodError because you are trying to call attributes as a class method:
subject { AssetIngester::Asset::GithubAsset.attributes(repo, asset_type) }
# ^^^^^^^^^^
although in your code, attributes is defined as an instance method.
But apart from that, you ask "how ruby initialize method can be tested" and apparently your test code is all about initialize and not about attributes, so let's start at the beginning:
describe '::attributes' do
# ...
end
You want to test initialize, so attributes should be initialize. And since initialize is an instance method (rather than a class method), :: should be #:
describe '#initialize' do
# ...
end
And your subject should be an instance of GithubAsset which is created via new1:
describe '#initialize' do
subject { AssetIngester::Asset::GithubAsset.new(repo, asset_type) }
# ...
end
With that in place, you can start writing your tests, e.g.:
describe '#initialize' do
subject { AssetIngester::Asset::GithubAsset.new(repo, asset_type) }
it 'sets the id attribute' do
expect(subject.id).to eq(131690)
end
end
1 In Ruby, you rarely invoke ::allocate and #initialize directly. So instead of:
obj = Array.allocate
obj.send(:initialize, 5) { |i| i ** 2 }
obj #=> [0, 1, 4, 9, 16]
you typically just call new and let it call allocate and initialize for you:
obj = Array.new(5) { |i| i ** 2 }
obj #=> [0, 1, 4, 9, 16]

Passing hash to #new results in array of values instead of correct value

With this setup in minitest,
def test_id
i = Item.new({
:id => 1,
:name => "Pencil",
:description => "You can use it to write things",
:unit_price => BigDecimal.new(10.99,4),
:created_at => Time.now,
:updated_at => Time.now,
:merchant_id => 2
})
assert_equal 1, i.id
end
For some reason, when created, calling the id attribute results in an array of all of the values:
[1,'Pencil','You can use it to write things',#<BigDecimal...>, 2018-07-24 14:43:36 -0600, 2018-07-24 14:43:36 -0600, 2]
instead of the integer 1.
In the item file, it looks like what you would expect
require 'bigdecimal'
require 'time'
class Item
attr_reader :id, :created_at, :merchant_id
attr_accessor :name, :description, :unit_price, :updated_at
def initialize(item_data)
#id = item_data[:id].to_i,
#name = item_data[:name],
#description = item_data[:description],
#unit_price = BigDecimal.new(item_data[:unit_price], 4),
#created_at = item_data[:created_at],
#updated_at = item_data[:updated_at],
#merchant_id = item_data[:merchant_id].to_i
end
end
Not really sure how this is happening.
Throwing a pry in the test method before the assertion and calling i results in
#<Item:0x00007f8cc48eb4f0
#created_at=2018-07-24 15:14:55 -0600,
#description="You can use it to write things",
#id=[1, "Pencil", "You can use it to write things", #<BigDecimal:7f8cc48eb4c8,'0.1099E2',18(27)>, 2018-07-24 15:14:55 -0600, 2018-07-24 15:14:55 -0600, 2],
#merchant_id=2,
#name="Pencil",
#unit_price=#<BigDecimal:7f8cc48eb4c8,'0.1099E2',18(27)>,
#updated_at=2018-07-24 15:14:55 -0600>
in the terminal.
It's your trailing commas in the initializer:
def initialize(item_data)
#id = item_data[:id].to_i, # <=
#name = item_data[:name], # <=
What they do is make ruby see the method like this:
#id = [item_data[id].to_i, #name = item_data[:name], ...]
It seems that the problem are the commas that you are adding at the end of each setting variable. Check with this code:
require 'bigdecimal'
require 'time'
class Item
attr_reader :id, :created_at, :merchant_id
attr_accessor :name, :description, :unit_price, :updated_at
def initialize(item_data)
#id = item_data[:id].to_i
#name = item_data[:name]
#description = item_data[:description]
#unit_price = BigDecimal.new(item_data[:unit_price], 4)
#created_at = item_data[:created_at]
#updated_at = item_data[:updated_at]
#merchant_id = item_data[:merchant_id].to_i
end
end

how to write strong parameters in rails

How can i Implement the below create action using strong parameters
def create
##user = User.find(params[:user_id])
#listing = Listing.find(params[:listing_id])
if current_user != #listing.user
#reservation=Reservation.new(user_id:current_user.id,listing_id:params[:reservation][:listing_id],price:params[:reservation][:price],
total:params[:reservation][:total],start_date:params[:reservation][:sdate],end_date:params[:reservation][:edate],
driver_name:params[:reservation][:driver_name],no_of_passengers:params[:reservation][:no_of_passengers],days:params[:reservation][:days],reservation_status:false,reservation_state: 'PENDING')
else
#reservation=Reservation.new(user_id:current_user.id,listing_id:params[:reservation][:listing_id],price:params[:reservation][:price],
total:params[:reservation][:total],start_date:params[:reservation][:sdate],end_date:params[:reservation][:edate],
driver_name:params[:reservation][:driver_name],no_of_passengers:params[:reservation][:no_of_passengers],days:params[:reservation][:days],reservation_status:false,reservation_state: 'BLOCKED')
end
#reservation.save
end
I have all the attributes coming from _form.html.erb accept user_id ,reservation_status and reservation_state.I can permit some attributes as:
def reservation_params
params.require(:reservation).permit(:start_date, :end_date, :price, :listing_id,:total,:driver_name,:no_of_passengers,:days)
How can I permit all the attributes including user_id, reservation_status and reservation_state for a user to complete the reservation.
Thanks in advance!
I would start with something like this:
def reservation_params
parameters = params.require(:reservation).permit(
:listing_id, :sdate, :edate, :driver_name, :no_of_passengers, :days
)
parameters.merge!(user_id: current_user.id, reservation_status: false)
if current_user != listing.user
parameters.merge!(reservation_state: 'PENDING')
else
parameters.merge!(reservation_state: 'BLOCKED')
end
end
def listing
#listing ||= Listing.find(params[:listing_id])
end

How to filter by foreign id and local attribute via belongs_to?

The following models are linked via belongs_to:
require 'mongoid'
class Sensor
include Mongoid::Document
field :sensor_id, type: String
validates_uniqueness_of :sensor_id
end
...
require 'mongoid'
require_relative 'sensor.rb'
class SensorData
include Mongoid::Document
belongs_to :sensor
field :date, type: Date
field :ozonMax1h, type: Float
field :ozonMax8hMittel, type: Float
index({ date: 1, sensor_id: 1 }, { unique: true })
end
Here is a Sinatra app which provides a few API paths based on these models:
require 'sinatra'
require 'csv'
require_relative './models/sensor.rb'
require_relative './models/sensor_data.rb'
configure do
Mongoid.load!('./mongoid.yml')
end
def prepare_for_export(sensor_data)
converted_data = sensor_data.asc(:date).map do |e|
{
sensor_id: e.sensor.nil? ? :null : e.sensor.sensor_id,
date: e.date,
ozonMax1h: e.ozonMax1h,
ozonMax8hMittel: e.ozonMax8hMittel
}
end
converted_data
end
def convert_to_json(sensor_data)
prepare_for_export(sensor_data).to_json
end
def convert_to_csv(sensor_data)
data = prepare_for_export sensor_data
csv_string = CSV.generate do |csv|
csv << data.first.keys
data.each do |hash|
csv << hash.values
end
end
csv_string
end
def get_recent
max_date = SensorData.max(:date)
SensorData.where(date: max_date)
end
def get_for_year(year)
SensorData.where(:date.gte => Date.new(year, 1, 1)).where(:date.lte => Date.new(year, 12, 31))
end
def get_for_sensor(sensor)
foo = SensorData.where(sensor_id: sensor)
puts "hallo"
return foo
end
get '/api/v1/stations' do
content_type :json
Sensor.all.map { |e| {sensor_id: e.sensor_id} }.to_json
end
get '/api/v1/sensordata/:year' do
content_type :json
convert_to_json get_for_year(params[:year].to_i)
end
get '/api/v1/sensordata/:year/csv' do
convert_to_csv get_for_year(params[:year].to_i)
end
get '/api/v1/recent' do
content_type :json
convert_to_json get_recent
end
I would like to output the SensorData for a particular sensor such as here:
/api/v1/stations/:sensor_id/sensordata/:year/csv
I am not sure what you are trying to do or even if you are still looking for an answer but here it goes. Something seems wrong with the models in the example you have here. Sounds like part of what you are doing would work if Sensor knows about sensor_data. So might need to add this to Sensor class:
has_many :sensor_data
Though the singular of data is datum. The class would be expected to be SensorDatum. If you can't change it, you need to tell Mongoid the class_name to expect in the has_many is actuall SensorData.
You CAN specify foreign_key in Mongoid with belongs_to.
You CANNOT filter with the belongs_to like you can with ActiveRecord, but you can use scopes outside of the belongs_to to get the same effect. Exampe:
belongs_to :sensor
scope :for_year, -> (year) { where(:date.gte => Date.new(2015,1,1)).where(:date.lte => Date.new(2015, 12, 31))}
or
belongs_to :sensor
def self.for_year year
where(:date.gte => Date.new(year,1,1)).where(:date.lte => Date.new(year, 12, 31))
end
So your query would become something like this:
sensor = Sensor.find_by(sensor_id: params[:sensor_id])
sensor.sensor_data.for_year(2015)

Resources