Unexpected syntax error - ruby-on-rails

given the following code from my custom model:
def categorize
#cv = Cv.find(params[:cv_id], :include => [:desired_occupations, :past_occupations, :educational_skills])
#menu = :second
#language = Language.resolve(:code => :en, :name => :en)
categorizer = CvCategorizer.new #cv, #language
categorizer.prepare_occupations
categorizer.prepare_occupation_skills
categorizer.prepare_education_skills
# fetch the data
#occupation_hashes = categorizer.occupations
#skill_hashes = categorizer.skills
# Sort the hashes
#occupation_hashes.sort! { |x,y| y.score <=> x.score}
#skill_hashes.sort! { |x,y| y.score <=> x.score}
#max = #skill_hashes.first.score
#min = #skill_hashes.last.score
end
The code creates a new instance of the CvCategorizer class and calls the three prepare methods in sequence. They all do funky stuff with data retrieved from the database. The code looks as follows:
# = CvCategorizer
# This class will handle the categorizing of a CV based upon the skills and occupations found in
# the CV. Because the controller originally had a huge chunk of code, this class will break up that
# login into seperate function calls and keep everything inside variables for easy access.
class CvCategorizer
# initializes a new instance of the CvCategorizer
def initialize cv, language
#cv = cv
#language = language
#occupations = []
#skills = []
end
# Prepares the occupation array by looking at the stored CV and collecting
# all the desired occupations and past occupations. These are stored inside
# the internal occupation array as a uniq list.
def prepare_occupations
all_occupations = #cv.desired_occupations.all(:include => :labels) + #cv.past_occupations.all(:include => :labels)
all_occupations.each do |occupation|
oc = OccupationCategory.new
oc.is_desired_work?= #cv.desired_occupations.include?(occupation)
oc.is_work_experience?= #cv.past_occupations.include?(occupation)
oc.occupation = occupation
if !#occupations.include?(oc)
#occupations << oc
else
obj = #occupations.select(oc)
obj.score += 1
obj.occupations= (obj.occupations & oc).uniq
end
end
=begin
all_occupations = #cv.desired_occupations.all(:include => :labels) + #cv.past_occupations.all(:include => :labels)
all_occupations.each do |occupation|
section = []
section << "Desired Work" if #cv.desired_occupations.include? occupation
section << "Work experience" if #cv.past_occupations.include? occupation
unless (array = #occupations.assoc(occupation)).blank?
array[1]+= 1
array[2] = (array[2] & section).uniq
else
#occupations << [occupation, 1, section, []]
end
end
=end
end
# Prepares the occupation skills of the CV by looping over all the stored
# occupations and retrieving the skills for them and storing them in the
# skills array.
def prepare_occupation_skills
# Loop over all the OccupationCategory objects currently present in the Categorizer.
#occupations.each do |oc|
# For each OccupationCategory object, retrieve all the associated skills, and
# include their label as well.
oc.occupation.skills.all(:include => :labels).each do |skill|
# Get the label of the current concept we're working with.
label = oc.occupation.concept.label(#language).value
# Check if the #skills array already contains a SkillCategory object with the
# skill we're currently checking.
if (sc = #skills.select{|scs| scs.skill == skill}).blank?
# The skill was not found, so create a new entry with the SkillCategory class and set the
# correct values for the various properties
sc = SkillCategory.new
sc.labels << label
sc.score= 1
sc.is_occupation_skill? = true
sc.skill= skill
else
# The skill was found in one of the SkillCategory objects. So we update the score by
# 1 and store the label of the current concept, unless that label is already present.
sc.labels << label unless sc.labels.include?(label)
sc.is_occupation_skill?= true
sc.score+= 1
end
end
end
=begin
#occupations.each do |array|
array[0].skills.all(:include => :labels).each do |skill|
unless (skill_array = #skills.assoc skill).blank?
label = array[0].concept.label(#language).value
skill_array[1]+= 1
skill_array[3] << label unless skill_array[3].include? label
else
#skills << [skill, 1, [], [array[0].concept.label(#language).value]]
end
end
end
=end
end
# Prepares the education skills by checking the CV and adding them to the
# skills array
def prepare_education_skills
# Loop over all the educational skills that are currently associated to the CV.
#cv.educational_skills.all(:include => :labels).each do |skill|
# Check if the #skills array already contains a SkillCategory object with the
# skill we're currently checking.
if (sc = #skills.select{|scs| scs.skill == skill}).blank?
# The skill was not found, so create a new entry with the SkillCategory class and set the
# correct values for the various properties
sc = SkillCategory.new
sc.labels << 'Education skills' unless sc.labels.include?('Education skills')
sc.score= 1
sc.is_educational_skill?= true
sc.skill= skill
else
# The skill was found in one of the SkillCategory objects. So we update the score by
# 1 and store the label of the current concept, unless that label is already present.
sc.labels << 'Education skills' unless sc.labels.include?('Education skills')
sc.is_educational_skill?= true
sc.score+= 1
end
end
=begin
#cv.educational_skills.all(:include => :labels).each do |skill|
unless (array = #skills.assoc skill).blank?
array[1]+= 1
array[3] << 'Education skills' unless array[3].include? 'Education skills'
else
#skills << [skill, 1, ['Education skills'], []]
end
end
=end
end
# Returns all uniq skills with their score and section found.
# array structure for each element
# - 0 : the skill object
# - 1 : the score for the skill
# - 2 : CV location of the skill
# - 3 : ESCO group of the skill
def skills
#skills
end
# Returns all uniq occupations with their score and section found.
# array structure for each element
# - 0 : the occupation object
# - 1 : the score for the occupation
# - 2 : the CV location of the occupation
# - 3 : empty array for occupations
def occupations
#occupations
end
end
When browsing to the relevant view in the application, i'm receiving the following error message from the server:
/home/arne.de.herdt/RubymineProjects/ESCO/app/models/cv_categorizer.rb:21:
syntax error, unexpected tIVAR, expecting kEND
oc.is_desired_work?= #cv.desired_occupations.include?(...
^
/home/arne.de.herdt/RubymineProjects/ESCO/app/models/cv_categorizer.rb:22:
syntax error, unexpected tIVAR, expecting kEND ...
oc.is_work_experience?= #cv.past_occupations.include?(occ...
^
/home/arne.de.herdt/RubymineProjects/ESCO/app/models/cv_categorizer.rb:69:
syntax error, unexpected '=', expecting kEND
sc.is_occupation_skill? = true
^
/home/arne.de.herdt/RubymineProjects/ESCO/app/models/cv_categorizer.rb:75:
syntax error, unexpected kTRUE, expecting kEND
/home/arne.de.herdt/RubymineProjects/ESCO/app/models/cv_categorizer.rb:108:
syntax error, unexpected kTRUE, expecting kEND
/home/arne.de.herdt/RubymineProjects/ESCO/app/models/cv_categorizer.rb:114:
syntax error, unexpected kTRUE, expecting kEND
It seems I'm missing something in the CvCategorize class, but I can't find the stuff missing. The IDE is not showing errors such as missing ends or anything.

Remove the question marks on oc.is_desired_work? and oc.is_work_experience? on lines 21 and 22.

ruby allows the question marks in method names, not the variables ( of any kind ) or object attributes.
the ruby way would be to add instance methods to your OccupationCategory class, like so:
class OccupationCategory
def is_desired_work?
...
end
def is_work_experience?
...
end
end
so you could later use it like
oc.is_desired_work?
oc.is_work_experience?

Related

How to create an instance of a class in Rails, giving each new instance 5 has_many through relationships

I want to make an instance of my Test class get five practice questions through a join class when it is initialised. If a test is an "exam" then it should just get 5 exam questions without a join class. (the question types have different models)
So far It doesn't behave the way I expect
self.practice_questions = []
it makes 5 join classes every time, but the array of self.practice_questions stays empty.
def get_questions
puts "ASDASDASDASDSAD"
array = []
if self.for_practice
puts "ASDASDASOASKODKSAOKDASODKOASKDSAOKDOASKDOASK"
PracticeQuestion.sort_for_selection[0...5].each do |question|
array << question
question.use_practice_question
end
elsif for_practice === false
puts self.exam_questions
if self.exam_questions.length ===0
grab 5 unused exam type questions
ExamQuestion.unused[0...5].each do |question|
puts "grabbing question #{question.title}"
question.test = self
question.use_question
end
end
puts "hello"
puts self.practice_questions.length
self.practice_questions ||= array
self.save
puts self.practice_questions.length
self.practice_questions.each {|question| puts question.title}
end
self.practice_questions ||= array will only assign the array if self.practice_questions is false or nil, are you sure it's one of those?
If practice_questions is a has_many, try one of this:
array.each do |el|
self.practice_questions << el
end
or:
self.practice_questions_ids = array.map(&:id)
https://guides.rubyonrails.org/association_basics.html#has-many-association-reference

Iterate through array of column names to pass to uniq.pluck()?

I have multiple columns I need to pull unique values from and compile an array of each unique value. Using uniq.pluck(:column_name) works, but how do I iterate over an array of column names?
react = []
fields = [reactivity_1, reactivity_2, reactivity_3, reactivity_4]
fields.each do |field|
puts "Parsing #{field}"
Raw.all.uniq.pluck(field).each do |r|
unless react.include? r
puts "Adding #{r} to Array."
react << r
else
puts "#{r} Exists."
end
end
end
Error:
NameError: undefined local variable or method `reactivity_1' for main:Object
You will need to make the column names strings or symbols, like this Ruby thinks it is a local varaible or method.
react = Set.new
fields = [:reactivity_1, :reactivity_2, :reactivity_3, :reactivity_4]
fields.each do |field|
puts "Parsing #{field}"
Raw.all.uniq.pluck(field).each do |r|
react << r
end
end
If you want to make sure that a collection does not contain duplicate, you can use a Set:
require "set"
set = Set.new
set << "foo"
set << "bar"
set << "bar"
puts set.size #> 2
I've rewritten your code sample to use Set.
Can you describe what you are trying to achieve? Perhaps there is an easier way to get the data out of the DB.

wrong number of arguments (given 0, expected 4)

I am getting this error for this set up. My thought is that the file cannot properly access the csv. That I am attempting to import. I've got to import from one csv to create another csv using the model date. What do I put in the controller and views to show the new csv / manipulated data? Basically how can I pass one csv file in a model for manipulation (orders.csv) and out into another csv file (redemption.csv) the code in the model is just telling model to calculate the existing numbers in orders.csv a certain way for export without this argument error?
The controller (I don't really know what to do here)
class OrdersController < ApplicationController
def index
orders = Order.new
end
def redemptions
orders = Order.new
end
end
The View (not confident about this either)
<h1>Chocolates</h1>
puts "#{order.purchased_chocolate_count}"
<%= link_to "CSV", orders_redemptions_path, :format => :csv %>
Model
require 'csv'
# Define an Order class to make it easier to store / calculate chocolate tallies
class Order < ActiveRecord::Base
module ChocolateTypes
MILK = 'milk'
DARK = 'dark'
WHITE = 'white'
SUGARFREE = 'sugar free'
end
BonusChocolateTypes = {
ChocolateTypes::MILK => [ChocolateTypes::MILK, ChocolateTypes::SUGARFREE],
ChocolateTypes::DARK => [ChocolateTypes::DARK],
ChocolateTypes::WHITE => [ChocolateTypes::WHITE, ChocolateTypes::SUGARFREE],
ChocolateTypes::SUGARFREE => [ChocolateTypes::SUGARFREE, ChocolateTypes::DARK]
}
# Ruby has this wacky thing called attr_reader that defines the available
# operations that can be performed on class member variables from outside:
attr_reader :order_value
attr_reader :chocolate_price
attr_reader :required_wrapper_count
attr_reader :order_chocolate_type
attr_reader :chocolate_counts
def initialize(order_value, chocolate_price, required_wrapper_count, order_chocolate_type)
#order_value = order_value
#chocolate_price = chocolate_price
#required_wrapper_count = required_wrapper_count
#order_chocolate_type = order_chocolate_type
# Initialize a new hash to store the chocolate counts by chocolate type.
# Set the default value for each chocolate type to 0
#chocolate_counts = Hash.new(0);
process
end
# Return the number of chocolates purchased
def purchased_chocolate_count
# In Ruby, division of two integer values returns an integer value,
# so you don't have to floor the result explicitly
order_value / chocolate_price
end
# Return the number of chocolate bonuses to award (which can include
# multiple different chocolate types; see BonusChocolateTypes above)
def bonus_chocolate_count
(purchased_chocolate_count / required_wrapper_count).to_i
end
# Process the order:
# 1. Add chocolate counts to the totals hash for the specified order type
# 2. Add the bonus chocolate types awarded for this order
def process
chocolate_counts[order_chocolate_type] += purchased_chocolate_count
bonus_chocolate_count.times do |i|
BonusChocolateTypes[order_chocolate_type].each do |bonus_chocolate_type|
chocolate_counts[bonus_chocolate_type] += 1
end
end
end
# Output the chocolate counts (including bonuses) for the order as an array
# of strings suitable for piping to an output CSV
def csv_data
ChocolateTypes.constants.map do |output_chocolate_type|
# Get the display string (lowercase)
chocolate_key = ChocolateTypes.const_get(output_chocolate_type)
chocolate_count = chocolate_counts[chocolate_key].to_i
"#{chocolate_key} #{chocolate_count}"
end
end
end
# Create a file handle to the output file
CSV.open("redemptions.csv", "wb") do |redemption_csv|
# Read in the input file and store it as an array of lines
input_lines = CSV.read("orders.csv")
# Remove the first line from the input file (it just contains the CSV headers)
input_lines.shift()
input_lines.each do |input_line|
order_value, chocolate_price, required_wrapper_count, chocolate_type = input_line
# Correct the input values to the correct types
order_value = order_value.to_f
chocolate_price = chocolate_price.to_f
required_wrapper_count = required_wrapper_count.to_i
# Sanitize the chocolate type from the input line so that it doesn't
# include any quotes or leading / trailing whitespace
chocolate_type = chocolate_type.gsub(/[']/, '').strip
order = Order.new(order_value, chocolate_price, required_wrapper_count, chocolate_type)
order.process()
puts order.purchased_chocolate_count
# Append the order to the output file as a new CSV line
output_csv << order.csv_data
end
end
In Your initialize method you are not provide default value to argument.
def initialize(order_value, chocolate_price, required_wrapper_count, order_chocolate_type)
When you are trying to run orders = Order.new it is expecting four argument and you haven't provide it.
One more issue. Your local variable name should be order not orders for proper naming convention.
To assign default values properly, you can look here.

Select item in array that matches one item in another array

Problem:
Get a single record from the contacts table where the first_name and last_name is equal to those given in the params. If there is more than one record found, then return the record that matches a domain.
def check_cache(params)
cached = where(first_name: params[:first_name], last_name: params[:last_name])
if cached.size > 1
# select the record with a matching one of params[:domains]
# cached #=> ['bob#gmail.com', 'bob#yahoo.com']
# params[:domains] #=> ['gmail.com', 'abc.com']
# result would be bob#gmail.com
end
cached
end
tried this in IRB
cached.select{|e| e =~ /(gmail.com)/}
but not sure how I would check each one in the params[:domains]
try this:
if cached.size > 1
params[:domains].each do |domain|
cached.select do |result|
result_domain = result.split("#").last
return result if result_domain == domain
end
end
end

Problem sorting an array

I'm mixing 2 arrays and want to sort them by their created_at attribute:
#current_user_statuses = current_user.statuses
#friends_statuses = current_user.friends.collect { |f| f.statuses }
#statuses = #current_user_statuses + #friends_statuses
#statuses.flatten!.sort!{ |a,b| b.created_at <=> a.created_at }
The #current_user_statuses and #friends_statuses each sort correctly, but combined they sort incorrectly, with the #friends_statuses always showing up on top sorted by their created_at attribute and the #current_user_statuses on the bottom sorted by their created_at attribute.
This is the view:
<% #statuses.each do |d| %>
<%= d.content %>
<% end %>
Try:
(current_user.statuses + current_user.friends.collect(&:statuses)) \
.flatten.compact.sort_by(&:created_at)
You can not daisy chain the flatten! method like that. flatten! returns nil if no changes were made to the array. When you sort nil nothing will happen.
You need to separate them:
#statuses.flatten!
#statuses.sort! { ... }
Here's how I'd do it:
Set up the classes:
class User
class Status
attr_reader :statuses, :created_at
def initialize(stats)
#statuses = stats
#created_at = Time.now
end
end
attr_reader :statuses, :friends
def initialize(stats=[], friends=[])
#statuses = Status.new(stats)
#friends = friends
end
end
Define some instances, with some time gaps just for fun:
friend2 = User.new(%w[yellow 2])
sleep 1
friend1 = User.new(%w[orange 1])
sleep 2
current_user = User.new(%w[green 1], [friend1, friend2])
Here's how I'd do it differently; Get the statuses in created_at order:
statuses = [
current_user.statuses,
current_user.friends.collect(&:statuses)
].flatten.sort_by(&:created_at)
Which looks like:
require 'pp'
pp statuses
# >> [#<User::Status:0x0000010086bd60
# >> #created_at=2011-07-02 10:49:49 -0700,
# >> #statuses=["yellow", "2"]>,
# >> #<User::Status:0x0000010086bc48
# >> #created_at=2011-07-02 10:49:50 -0700,
# >> #statuses=["orange", "1"]>,
# >> #<User::Status:0x0000010086bb30
# >> #created_at=2011-07-02 10:49:52 -0700,
# >> #statuses=["green", "1"]>]
I'm just building a temporary containing array to hold the current_user's status, plus the status of all the friends, then flattening it.
The (&:statuses) and (&:created_at) parameters are Rails short-hand for the statuses method of the instance, or created_at method of the instance.
#statuses = (#current_user_statuses + #friends_statuses).sort_by(&:created_at)
I know there are several solutions posted for your question. But all of these solutions can kill your system when the number of statuses grow in size. For this dataset, you have to perform the sorting and pagination in the database layer and NOT in the Ruby layer
Approach 1: Simple and concise
Status.find_all_by_user_id([id, friend_ids].compact, :order => :created_at)
Approach 2: Long and efficient
class User
def all_statuses
#all_statuses ||=Status.all( :joins => "JOIN (
SELECT friend_id AS user_id
FROM friendships
WHERE user_id = #{self.id}
) AS friends ON statuses.user_id = friends.user_id OR
statuses.user_id = {self.id}",
:order => :created_at
)
end
end
Now you can get the sorted statuses in single query:
user.all_statuses
PPS: If this is my code I would further optimize the SQL. Refer to this answer for some more details.

Resources