Rails 4 - Uninitialized constant Mongo Model - ruby-on-rails

I am attempting to setup MongoHQ using Heroku and rails 4. I have everything setup correctly to my knowledge, but I'm now getting this error:
uninitialized constant Job::TempEmailContactStoreCsv
This is the Job model where error is happening:
class Job < ActiveRecord::Base
belongs_to :user
def store_email_contact_csv(file)
contact_array = csv_to_array(file)
TempEmailContactStoreCsv.create(email_contact_array: contact_array, job_id: id)
end
end
And my mongo model:
class TempEmailContactStoreCsv
include Mongoid::Document
field :email_contact_array, type: Array
field :job_id
def self.store(job_id, email_contact_array)
r = TempEmailContactStoreCsv.find_by(job_id: job_id)
if (r.nil?)
TempEmailContactStoreCsv.create!(job_id: job_id, email_contact_array: email_contact_array)
end
end
def self.exists?(job_id)
r = TempEmailContactStoreCsv.find_by(job_id: job_id)
return r.nil? == false
end
def self.retrieve(job_id)
return TempEmailContactStoreCsv.find_by(job_id: job_id)
end
def self.delete(job_id)
r = TempEmailContactStoreCsv.find_by(job_id: job_id)
r.destroy unless r.nil?
end
end
So it seems that my mongo model is not being initialized, and the namespacing seems weird to me also.
Any thoughts as to what is causing this error and how to fix it?

For rails to load a class automatically, the file must be within rails load path (which includes app/models so you are fine there) and the file name should be the camelcased version of the class name.
In your case the file name should be temp_email_contact_store_csv.rb not temp_email_store_csv.rb

Related

Rails ActionView::Template::Error undefined method `count' Resolver

Note: I am using ruby 2.5.1 and rails 4.2.10
I am getting an error in my rails project and I believe it is because one of my classes is called Resolver. Here are the relevant files:
Migration
class CreateResolvers < ActiveRecord::Migration
def change
create_table :resolvers do |t|
t.belongs_to :user, index: true
t.string :name
end
end
end
Class
class Resolver < ActiveRecord::Base
belongs_to :user
end
Controller
class ResolversController < ApplicationController
def create
ent = Entity.new(entity_params)
ent.save!
redirect_to '/getting_started/resolvers'
end
def update
resToUpdate = Resolver.find(params['id'])
resToUpdate.update(resolver_params)
redirect_to '/getting_started/resolvers'
end
private
def resolver_params
params.require('resolver').permit(
:name
)
end
end
So here is my error: When I go into the rails console and do Resolver.count, it works fine, but in my actual html page, I have the line:
<% if (Resolver.count > 0) %>
and I am getting an error of:
undefined method 'count' for ActionView::Resolver:Class
Now, obviously that ActionView::Resolver:Class is not correct. I tried changing them to ::Resolver and ActiveRecord::Base::Resolver and neither worked. How can I use a class named Resolver without rails assuming it is this ActionView::Resolver
Having queries in the view is an antipattern.
The correct way of doing it anyway is to do it in the controller and pass the variable to the view.
#resolvers_count = Resolver.count and in the view check on if #resolvers_count > 0
a better way is
#resolvers_exist = Resolver.exists? and then if #resolvers_exist
Isn't it better to define a instance variable at the controller like
#resolver_count = Resolver.count so you can reach the count by calling #resolver_count on your view?

Pass in ruby variable to a class factory ruby script

My intention is to create custom error classes in various places for my Rails application since most of the error classes have the same methods. I have decided to create a YAML file to contain all the information from various error classes, and use a class factory script to generate all the classes in runtime. Here is what I have:
chat_policy.rb
class ChatPolicy; ... end
class ChatPolicy::Error < StandardError
ERROR_CLASSES = GLOBAL_ERROR_CLASSES['chat_policy']
ERROR_CLASSES.each do |cls|
const_set(cls['class_name'], Class.new(ChatPolicy::Error) {
attr_reader :object
def initialize(object)
#object = object
end
define_method(:message) do
cls['message']
end
define_method(:code) do
cls['code']
end
})
end
the GLOBAL_ERROR_CLASSES is loaded from YAML.load and turned to an object.
error_classes.yml
chat_policy:
- class_name: UserBlacklisted
message: You are not allowed to do this
code: ECP01
- class_name: UserSuspended
message: You are not allowed to do this
code: ECP02
- class_name: UserNotEligibleToRent
message: You are not allowed to do this
code: ECP03
- class_name: MembershipTierNotAllowed
message: You are not allowed to do this
code: ECP04
* __ Question is __ *
Now I have other files like register_policy, checkout_policy, discount_policy ..etc. It would be very duplicated if I have to do the class generation in every policy file. I wonder if I can shorten the code to something like this:
chat_policy_intended.rb
class ChatPolicy::Error < StandardError
ERROR_CLASSES = GLOBAL_ERROR_CLASSES['chat_policy']
error_class_factory(ChatPolicy::Error, ERROR_CLASSES)
end
discount_policy_intended.rb
class DiscountPolicy::Error < StandardError
ERROR_CLASSES = GLOBAL_ERROR_CLASSES['discount_policy']
error_class_factory(DiscountPolicy::Error, ERROR_CLASSES)
end
error_clas_factory.rb
ERROR_CLASSES.each do |cls|
const_set(cls['class_name'], Class.new(/*class_variable*/) {
attr_reader :object
def initialize(object)
#object = object
end
define_method(:message) do
cls['message']
end
define_method(:code) do
cls['code']
end
})
end
What I tried
I tried to create a .rb file basically copying the class factory script. And use eval method to eval it in runtime, but it seems I can pass in variables into the script
eval File.read(File.join(Rails.root, 'lib', 'evals', 'error_class_generator.rb'))
What should I do?
I appreciate the effort of avoiding to repeat yourself at all costs, but I find your code quite complex for the problem you're trying to solve, namely send errors to your app users.
How about sticking to the a simpler < MyAppError inheritance hierarchy to avoid the duplicated code?
class MyAppError < StandardError
attr_reader :object
def message(message)
# does stuff
end
def code(code)
# also does stuff
end
end
class ChatPolicyError < MyAppError
def message(message)
'[CHAT POLICY]' + super
end
end
class UserBlacklisted < ChatPolicyError
def message(message)
# Does stuff too
super
end
end
[...] # You get the idea

Undefined class method using Rails Concerns

I did everything pretty much as described here: question
But I keep getting error:
NoMethodError: undefined method `parent_model' for Stream (call 'Stream.connection' to establish a connection):Class
In model/concerns faculty_block.rb
module FacultyBlock
extend ActiveSupport::Concern
included do
def find_faculty
resource = self
until resource.respond_to?(:faculty)
resource = resource.parent
end
resource.faculty
end
def parent
self.send(self.class.parent)
end
end
module ClassMethods
def parent_model(model)
##parent = model
end
end
end
[Program, Stream, Course, Department, Teacher].each do |model|
model.send(:include, FacultyBlock)
model.send(:extend, FacultyBlock::ClassMethods) # I added this just to try
end
In initializers:
require "faculty_block"
method call:
class Stream < ActiveRecord::Base
parent_model :program
end
It seems that the Stream is loaded before loading concern, make sure that you have applied the concerns inside the class definition. When rails loader matches class name for Stream constant, it autoloads it before the finishing evaliation of the faculty_block, so replace constants in it with symbols:
[:Program, :Stream, :Course, :Department, :Teacher].each do |sym|
model = sym.to_s.constantize
model.send(:include, FacultyBlock)
model.send(:extend, FacultyBlock::ClassMethods) # I added this just to try
end

naming convention in rails. why isn't my services file being found in the app folder?

I created a services file called TitleParser in app/services... a custom made folder. The file is called titleparser.rb
class TitleParser
attr_reader :connection
def initialize(orig_url)
#connection = Faraday.new(orig_url)
end
def obtain_title
response = parse(connection.get)
require 'pry' ; binding.pry
end
private
def parse(response)
JSON.parse(response.body)
end
end
In my model, I in app/models I have a model called Link that calls it.
class Link < ActiveRecord::Base
before_create :shorten_url
before_create :set_defaults
def shorten_url
self.short_url = "bit.ly-remix/" + SecureRandom.urlsafe_base64(6)
end
def set_defaults
self.clicks = 0 if clicks.blank?
self.title = TitleParser.new(orig_url).obtain_title
end
end
I was getting a undefined Link::TitleParser for hours until I renamed the file in services to title_parser.rb. What is going on here? What conventional rule is this?
This is a standard Rails naming convention issue that you've run into. Note how you've named the class:
class TitleParser
With that name, Rails will want a file named title_parser.rb

How can I share data with a concern in Rails 4.2?

I am attempting to use Rails Concerns (or even a bare Module mixin) to share methods across some of my models.
Given a simple model, I am storing some encoded data in one of the
fields:
class DataElement < ActiveRecord::Base
include EmbeddedData
ENCODED = %w(aliases)
end
I’ve then made a concern with the needed methods for managing the data:
module EmbeddedData
extend ActiveSupport::Concern
included do
after_find :decode_fields
before_save :encode_fields
#decoded = {}
end
def decoded(key, value = false)
#decoded[key][:value] if #decoded.has_key? key
end
def decode_fields
#decoded = {} if #decoded.nil?
ENCODED.each do |field|
if attributes[field]
#decoded[field] = {
value: JSON.parse(attributes[field]),
dirty: false
}
end
end
end
def encode_fields
ENCODED.each do |field|
if decoded[field] && decoded[field][:dirty]
attributes[field] = #decoded[field][:value].to_json
end
end
end
end
Given this setup, I get the error uninitialized constant EmbeddedData::ENCODED
If I change the reference to self::ENCODED in the Concern I get the error:
# is not a class/module
I've even tried making a method on the concern register_fields that I can then call from the model, but the model just throws an unknown method error.
Running out of ideas here and looking for help.
So it turns out the way to access the class constant is:
self.class::ENCODED

Resources