Rhomobile 4.1.1 - How to create local (non-sync) table - ruby

Following the documentation I am trying to create my first model in Rhomobile 4.1.1
It is advised to create a Ruby class, and said that the framework would create the necessary table. But I must have misunderstood because it is not working that way.
model in app/Auth/auth.rb
class Auth
include Rhom::FixedSchema
set :schema_version, '0.1'
property :session_token, :string
property :remember_token, :string
def self.auth_record
#auth_record ||= begin
if find(:count) == 0
create
else
find :first
end
end
end
end
As you can see I am trying to create a fixed schema single record table. I am not using RhoSync. As a result there is no table created, I am missing a step. Any hint appreciated. Thanks

My mistake was to have
require 'Auth/auth'
On top of one of my files.
The framework relies on const_missing to load and initialize the model (inject dependencies, create tables, ...). As I explicitly required the source file, the constant was already defined therefore Rhodes internal did not perform the needed initialization. Removing the require fixed the problem.
Lesson learned, also I would says that 1) this is not really solid coding and 2) this is completely undocumented.

Related

Why do I need to initialize a Cucumber DataTable with a Cucumber DataTable?

We recently started to drag a very old Rails app up to date (or at least out of obsolescence). One of the changes was an update of Cucumber from 1.3.x to 2.99.
Many of our rspec specs on this app used a helper for loading test data which leveraged Cucumber::Ast::DataTable. (The helper declared its own subclass which inherited from Cucumber::Ast::DataTable.) This was deprecated, so as suggested, I replaced the inheritance with Cucumber::MultilineArgument::DataTable.
The subclass looks like this:
class ParsedTable < ::Cucumber::MultilineArgument::DataTable
def initialize(string)
super(string.split("\n").map do |line|
line = line.split('|').map(&:squish)
line.slice(1, line.length)
end)
end
end
Then there are a bunch of test helpers which create test data like this (assume "role" is a model we'll be testing against):
def create_roles(string)
table = ParsedTable.new(string)
table.hashes.each do |hash|
create :role,
name: hash['Name'],
short_name: hash['Short Name'],
contracted_work_day: hash['Contracted workday in minutes']
end
end
These helpers get called like this:
create_roles <<-eos
| Name | Contracted workday in minutes |
| Therapist | 390 |
eos
But when that kind of call goes in, I get ArgumentError: data must be a Core::Ast::DataTable. The stack says this exception is from lib/cucumber/multiline_argument/data_table.rb:93:in 'initialize' which is the super call in the ParsedTable definition.
I've been trying to chase this around the Cucumber source and I can't figure out what I'm doing wrong.
The API documentation for Cucumber states that the constructor for Cucumber::MultilineArgument::DataTable takes a Core::Ast::DataTable object.
Source: https://www.rubydoc.info/gems/cucumber/Cucumber/MultilineArgument/DataTable#constructor_details
You will need an instance of Core::Ast::DataTable rather than custom parsing it from a string.
Creates a new instance. +raw+ should be an Array of Array of String or an Array of Hash You don't typically create your own DataTable objects - Cucumber will do it internally and pass them to your Step Definitions.
Source: https://www.rubydoc.info/gems/cucumber-core/1.3.1/Cucumber/Core/Ast/DataTable#constructor_details
It looks like cucumber should have already parsed the table as a Core::Ast::DataTable object in the step binding, so all you should need to do is pass this along to the constructor of your ParsedTable class.
When this isn't available, then you'll need to provide an array of array of strings instead.
Greg Burghardt's answer has the right cause for this; the Cucumber::MultilineArgument::DataTable class requires a Core::Ast::DataTable as an argument, which wasn't true of the old Cucumber::Ast::DataTable. (This class in general is a bit of a moving target between Cucumber 1.4.x and the current version.)
In the end I solved this by avoiding the problem. Looking carefully at the methods which used the custom ParsedTable class, I saw they didn't really depend on the class, but instead counted on calling hashes on each instance. What I needed was something which responded to hashes with the appropriate response.
So, rather than subclassing Cucumber::MultilineArgument::DataTable simply to get a custom constructor, I replaced the subclass definition with a method which accepted a string, split it into rows, and fed that Array of rows to Cucumber::MultilineArgument::DataTable#from. That returned an instance of Cucumber::MultilineArgument::DataTable which I could call hashes on. And that works.

Using Grape to create an API with just Ruby objects instead of a database or Rails

I am trying to use Grape to create an API using only Ruby objects. I do not want to use a database/Rails/ActiveSupport/etc -- just Rack, Ruby, and Grape.
I have defined a class for a Directory that I want to interact with through the API. So Directory#sort_by("last_name") returns JSON data with a list of People objects in my Directory. I also have a method Directory#create_person(attributes) that takes a string and uses it to add Person objects to the Directory. The directory is populated with people upon creation.
I am new to working with Rack and Grape, so I'm not sure where/how to create my Directory object and have it accessible through the GETs/POSTs in my Grape API class. Using a class variable inside this class appears to work, i.e.,:
module API
class DirectoryAPI < Grape::API
format 'json'
##directory = Directory.new("1.txt", "2.txt", "3.txt")
get 'last_name' do
##directory.sort_by("last_name")
end
end
end
but using class variables just seems wrong. Is there any better/cleaner way to create my Directory object? Perhaps inside my config.ru file? Or could I do it through a class method inside of Directory somehow?
What you are looking for is a singleton:
Usually singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.
Unfortunately, Ruby just doesn't play well with singletons. But you can use a "class consisting of only class methods," the second strategy advocated in this article.
I believe that you are working on a coding challenge that I completed a few months ago. In my answer, I used a "class consisting of only class methods" called API::Store. Here's the output from rspec -fd:
API::Store
::add
adds record to store
appends data line to file
::has_line?
instantiates a record from the data line
without the record in the store
should equal false
with the record in the store
should equal true
::new
should raise NoMethodError
::records
with original file
on initial access
should eq Records
on subsequent access
should eq Records
when file replaced
should eq OtherRecords
Finished in 0.07199 seconds (files took 2.68 seconds to load)
9 examples, 0 failures
Note that Store can't be instantiated; it throws a NoMethodError if you try. That's not a problem, though. In the Grape endpoint you can call Store.records to access the data.
As for sorting the records, this should be done in another class. Why should a Store or a Directory be sorting the data in its files?
Finally, you asked where to do the initial preparation (not initialization, of course). You can prepare your singleton in config.ru, so that it is ready when the application starts:
# config.ru
# load application code here
file = File.open('data/records.txt', 'a+')
at_exit { file.close }
API::Store.file = file
run API::Base
The challenge's instructions say "You may use any resources you need to complete it," so presumably, asking on Stack Overflow is allowed. If you are doing this challenge for a job application, please do mention so when you ask questions, because it's only fair for those answering to be informed. It would be wise to also mention at your interview that you got help on SO. Good luck, and happy coding.
The main problem I see with your example is not the use of class variables exactly, but instantiating your data inline in the API controller code. Ideally the data should be more self-contained, so you can access the exact same data from other places in your code. If you make an API similar to a light-weight data access module, then you will be using a familiar pattern in your route controllers - also it will become easy to migrate to using SQL or other data store if and when you need to.
There are lots of valid approaches, but I might create a new singleton object to represent your data source, and connect that to your hard-coded data as if it were tables. The end result here would feel a little like using Sequel (but you could follow any other pattern that you prefer):
inline_data.rb
module InlineDB
TABLES = Hash[
:directory => Directory.new("1.txt", "2.txt", "3.txt")
]
def self.[] table_name
TABLES[table_name]
end
end
app.rb
require_relative 'inline_data' # actual path may be more structured
module API
class DirectoryAPI < Grape::API
format 'json'
get 'last_name' do
InlineDB[:directory].sort_by("last_name")
end
end
end

Where and how should I add this new 'non-rails-way' method in my Rails application

I've written a small method to query and retrieve from an MS SQL 2008 server and I am not sure where to put the code in my rails app.
The scenario:
I am writing a Ruby and Rails app with a connection to a legacy MS SQL 2008 server DB.
A lot is working as expected, which is nice.
For now I work off a copy of the legacy DB and I treat it as readonly. It's big (7000+ tables some of which have over 40 million records). I am using it 'as-is' and don't want to change any of the underlying schema.
I do want to extend some very server-specific functionality. For instance, I make use of:
thing = ActiveRecord::Base.connection.exec_query(my_query_string_here)
... and it works. The result is an array that contains a hash and I can get to the relevant hash value by using:
thing[0][""]
... which works.
So, I thought I should write a method to make this easier and I wrote:
Class Tool < ActiveRecord::Base
def self.queryRDW(x)
res=ActiveRecord::Base.connection.exec_query(x)
ret=res.to_hash
return ret[0][""]
end
end
and put it in config/initializers/tool.rb Unfortunately, webrick complains about the file during boot with the following cryptic error:
.../config/initializers/tool.rb:7: syntax error, unexpected keyword_end, expecting $end (SyntaxError)
I recognize that this is not an out-of-the-box rails-way of doing things, so please don't remind me. (My struggles remind me often enough)
My question:
Where should I put this code so that I can invoke it from within a controller or a view in my rails app? Does this need to be a new Class method or something else?
Many thanks!
Addendum:
I changed Class to class (doh!)
I moved tool.rb into lib/
I changed tool.rb to now be:
module Tool
def self.queryRDW(x)
res = ActiveRecord::Base.connection.exec_query(x)
res.to_hash[0][""]
end
end
but doing this in app/views/stats.html.erb
thing=queryRDW("mysql string")
gets me an 'undefined method error'
Addendum 2
I made the directory app/concerns and put tool.rb there.
When I use:
<%=queryRDW("myStringHere")%>
in:
app/views/stats.html.erb
I get:
undefined method `queryRDW' for #<#<Class:0x0000000378ccf8>:0x00000003c1ce58>
You need to lowercase the keyword class in line 1.
I'd also say that this class doesn't need to inherit from ActiveRecord::Base — and doesn't even really need to be a class — if it's simply a wrapper around exec_query. There's nothing "wrong" with this, but if you never intend to instantiate an object of this class, you could just create a simple utility module:
module Tool
def self.queryRDW(x)
res = ActiveRecord::Base.connection.exec_query(x)
res.to_hash[0][""]
end
end
You can save this file in a couple of places:
lib/tool.rb. If you're using Rails 3, you'll need to add (or uncomment) this line in config/application.rb:
# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
app/concerns/tool.rb. This will automatically be detected by Rails 3.
I generally use app/concerns for tools that are entirely application-specific and lib for utilities that I might reuse among several different applications.
I wouldn't put this in config/initializers. This seems like code you'd put in app/models.
The error you're getting is syntax related, so double check the syntax.
To answer your question more directly, though, it's acceptable to put this stuff in your model if it's model related (in other words, part of your business domain). If it is something extraneous or orthogonal to your domain, I'd put it in lib.
Hope this helps.

ActiveRecord 3.1.0 multiple databases

I'm trying to upgrade the ActiveRecord gem to the latest 3.1.0 release and seeing a lot of exceptions being raised, I think it's due to how we handle multiple databases.
For each of our databases we specify a separate base class which inherits from ActiveRecord::Base, and call establish_connection in there. There are no cross-database relations. This has worked fine for us up until now.
Having upgraded to ActiveRecord 3.1.0 I'm seeing that it fails with an ActiveRecord::ConnectionNotEstablished exception, when traversing relations (i.e. it will successfully pull a single entity or set of them from the DB, but fails when navigating to a related class).
The top line of the backtrace is C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.1.0/lib/active_record/connection_adapters/abstract/connection_pool.rb:410:in 'retrieve_connection', so I dug into this a little. The method is defined as follows:
def retrieve_connection(klass) #:nodoc:
pool = retrieve_connection_pool(klass)
(pool && pool.connection) or raise ConnectionNotEstablished
end
My simple test (puts Customer.first.address) calls retrieve_connection 3 times. Twice with Customer as the klass parameter, and once with ActiveRecord::Base as the parameter - which is when it fails as establish_connection has not been called for ActiveRecord::Base.
To the actual question then - is there a new recommended way of handling multiple database connections in ActiveRecord? If so, what is it?
If not, what could be causing this problem?
I ran into the same issue yesterday while upgrading to ActiveRecord 3.1.0. I can't speak to whether there is a new recommended way of handling multiple database connections in ActiveRecord 3.1, but I did find a way to unblock myself.
It appears a connection must now be established on ActiveRecord::Base in order for it to determine the table name lengths/rules of the adapter. Along with the rest of my connections established in my database initializer, I now also have an ActiveRecord::Base connection established to one of my DBs (it doesn't matter which one).
I'd like to think there's a better solution to be found, but I'm happy to be unblocked for now.
I am using this solution - What I was seeing was that when establish_connection was called in each of the OtherDb classes - there seemed to be alot of overhead reloading table definitions and I would randomly see issues every time the class def was reloaded.
# The idea here is to specify that a given model should use another
# database without having to change the entire inheritance hierarchy
# declare model for table in primary connection
class Bar < ActiveRecord::Base
# assume we have logic here that we don't want to refactor into a module
# but we do want to inherit in OtherDb::Bar
end
module Foo
# base model in Foo namespace - uses another db
class BaseConnection < ActiveRecord::Base
# OtherDb::Title.database contains a db config hash
# This would probably go in the initializers
establish_connection OtherDb::Title.database
end
# module used to override db connection
module OtherDb::Base
def retrieve_connection
# connection_handler.retrieve_connection(self) # normal behavior
connection_handler.retrieve_connection(Foo::BaseConnection) # use db from Foo::BaseConnection
end
end
# Foo::Bar is identical to ::Bar but is in another db
class Bar < ::Bar
extend OtherDb::Base
end
end

Using Modules to Define Properties with Datamapper

so I'm setting up some models and they are based off of 2 abstract base classes (or rather they used to be classes). After running into a lot of trouble with Datamapper's handling of STI for my use case, which appears to be an open bug on their lighthouse page, I decided instead to just do modules to define all the properties to keep my models DRY. Unfortunately, I'm having a scoping issue, and what complicates matters worse is that I have to use 2 levels of inheritance. Here's my code:
module Part
def self.included(receiver)
receiver.class_eval do
include DataMapper::Resource
property :id, Serial
#other junk
end
end
end
module HardDrive
def self.included(receiver)
receiver.class_eval do
include Part
property :kind, Enum[:magnetic, :flash]
#buncha crap here
end
end
end
class Fujitsu
include HardDrive
property :rev, String
end
The error I get is:
uninitialized constant HardDrive::Enum (NameError)
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:80:in `const_missing'
from ./app/models/hard_drive.rb:6:in `included'
from ./app/models/hard_drive.rb:4:in `class_eval'
from ./app/models/hard_drive.rb:4:in `included'
from ./app/models/hard_drives/fujitsu.rb:2:in `include'
from ./app/models/hard_drives/fujitsu.rb:2
I'm at a loss here. Anyone know of how I could solve this or better yet, a smarter way I could do this?
It seems to me that Enum is defined under the DataMapper modules and the HardDrive scope does not resolve it. (Want to know why ?)
Just put DataMapper::Enum instead of Enum and it should work.
In a more general discussion, are you sure you really need these abstractions ? One drawback I see in your code is that you won't be able to query your database for parts and harddrives because the logic is stored in ruby modules instead of in the database.
Update (after comment from author)
The general answer is: forget about STI. While ORM are nice to have, the best part of them is SQL backend abstraction. While they give you the impression that you can have a persisten object model, the abstractions often leak and STI is a good example. I won't go in large details here but you can find resources online. Best is that you stay close enough to SQL modelling best practices, like one-one, one-many and many-many relationsships.
Here is an updated version. I didn't test it and the method names are probably wrong, but you will get the idea:
class Part
property :serial_number
has_one Manufacturer
end
class HardDisk
property :technology
property :platters
property :model
#...
is_one Part
end
class Manufacturer
property :name #Fujitsu, ...
property :website
#...
has_many HardDisk, [:trough=>Part]
end

Resources