Sequel Model set_schema not found - ruby

Can any one volunteer why the class below fails?
... src/model/user.rb:18: undefined method `set_schema' for User:Class (NoMethodError)
I've looked in the Sequel-3.0 lib/ folder and the set_schema method is defined in a ClassMethods module.
I'm sure the solution is simple. I was thinking it should work "as is":
require 'sequel'
class User < Sequel::Model(:user)
set_schema do
set_primary_key :id
String :name
end
end

Recommended way ...
LOGGER = Object.new()
def LOGGER.method_missing( name, args )
puts "[#{name}] #{args}"
end
Sequel::Model.plugin(:schema) # I worked this out, but I can't find it documented
DB = Sequel.sqlite('sql_test.db', :loggers => [LOGGER] )
unless DB.table_exists?( :user )
DB.create_table :user do
set_primary_key :id
String :name
String :password
String :eMail
end #create_table
end #table exists
class User < Sequel::Model(:user)

The answer is to call up the plug-in for schema managing. Viz.
require 'sequel'
require 'logger'
LOGGER = Object.new()
def LOGGER.method_missing( name, args )
puts "[#{name}] #{args}"
end
**Sequel::Model.plugin(:schema)** # I still didn't find this documented
DB = Sequel.sqlite('sql_test.db', :loggers => [LOGGER] )
class User < Sequel::Model(:user)
set_schema do
set_primary_key :id
String :name
end
end

Yep Sequel::Model.plugin(:schema) worked for me too. Can't see it in the docs and I'm perplexed as to why, since I have another working project that uses set_schema without fuss.

Related

active record with ruby (not rails)

I am using active record with ruby (but not rails). I am using sqlite3 which has a test.db on file (not just in-memory). When I run the following code snippet using user.create, it complains about argument error (and when I use use.save, it throws an active record exception. Any idea what I might be doing wrong? Thanks
require 'rubygems'
gem 'activerecord'
require 'sqlite3'
require 'active_record'
ActiveRecord::Base.logger = Logger.new(STDERR)
#ActiveRecord::Base.colorize_logging = false
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:host => "localhost",
:database => 'test.db'
)
class User < ActiveRecord::Base
#attr_accessible :email, :full_name
attr_accessor :email
attr_accessor :full_name
validates :email, presence: true, uniqueness: true
def initialize(email, full_name)
#email = email
#full_name = full_name
end
end
puts "full_name for user:"
full_name = gets.chomp
puts "email address:"
email = gets.chomp
user = User.new(email, full_name)
#user.save
user = User.create!(email: '', full_name: '')
Exception in first case (with User.create!):
main.rb:42:in `initialize': wrong number of arguments (1 for 2) (ArgumentError)
from /var/lib/gems/1.9.1/gems/activerecord-4.2.4/lib/active_record/inheritance.rb:61:in `new'
from /var/lib/gems/1.9.1/gems/activerecord-4.2.4/lib/active_record/inheritance.rb:61:in `new'
from /var/lib/gems/1.9.1/gems/activerecord-4.2.4/lib/active_record/persistence.rb:50:in `create!'
from main.rb:55:in `<main>'
It is complaining about the new method. According to the documentation: (http://api.rubyonrails.org/classes/ActiveRecord/Base.html), you don't need the initialize, because when you inherit from ActiveRecord::Base, you need to initialize your objects with a hash.
user = User.new({email: email, full_name: full_name})
# or
user = User.new(email: email, full_name: full_name)
# then
user.save
You need to drop the initialize and the attr_accessor from your code.
Try to comment User#initialize method and create new user like this:
User.create! email: 'halk#mail.com', full_name: 'Halk'
Explanation
When you declare AR model by heritage from ActiveRecord::Base class you don't need to define your own #initialize method. But you do. When you call User::create! method, you pass only one argument - Hash with two pairs (with email and full_name keys). But User#initialize define two parameters - email and full_name separately. So Ruby exception raise and talk about it:
wrong number of arguments (1 for 2) (ArgumentError)

host and port in a grape entity

Im trying to get the host and port in a grape-entity when generating an url
class Person < Grape::Entity
expose :url do |person,options|
"http://#{host_somehow}/somepath/#{person.id}"
end
end
I´ve tried examining the options hash but the 'env' hash is empty.
Following works for me, Grape 0.6.0, Grape-Entity 0.3.0, Ruby 2.0.0:
require 'grape'
require 'grape-entity'
# in reality this would be Active Record, Data Mapper, whatever
module Model
class Person
attr_accessor :identity, :name
def initialize i, n
#identity = i
#name = n
end
end
end
module APIView
class Person < Grape::Entity
expose :name
expose(:url) do |person,opts|
"http://#{opts[:env]['HTTP_HOST']}" +
"/api/v1/people/id/#{person.identity}"
end
end
end
class MyApp < Grape::API
prefix 'api'
version 'v1'
format :json
resource :people do
get "id/:identity" do
person = Model::Person.new( params['identity'], "Fred" )
present person, :with => APIView::Person
end
end
end
Quick test:
curl http://127.0.0.1:8090/api/v1/people/id/90
=> {"name":"Fred","url":"http://127.0.0.1:8090/api/v1/people/id/90"}
Finally ended up with sending the host as a option to the entity
class Person < Grape::Entity
expose :url do |person,options|
"http://#{options[:host]}/somepath/#{person.id}"
end
end
get '/' do
#persons = Person.all
present #persons, with: Person, host: request.host_with_port
end

Uninitialized constant (NameError) when using FactoryGirl in module

Here's the error I'm getting when I try to run my tests with RSpec:
C:/Ruby193/lib/ruby/gems/1.9.1/gems/activesupport-3.2.11/lib/active_support/infl
ector/methods.rb:230:in `block in constantize': uninitialized constant User (Nam
eError)
I'm trying to run FactoryGirl with RSpec but without Rails. Here are the files that take part in the testing:
user_spec.rb
require 'spec_helper'
module Bluereader
describe User do
describe 'login' do
user = FactoryGirl.build(:user)
end
describe 'logout' do
end
describe 'create_account' do
end
describe 'delete_account' do
end
end
end
spec/spec_helper
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rspec'
require 'lib/bluereader'
require 'factory_girl'
FactoryGirl.find_definitions
spec/factories.rb
require 'digest/sha1'
FactoryGirl.define do
sequence(:username) { |n| "user-#{n}" }
factory :user do
username
encrypted_password Digest::SHA1.hexdigest('password')
full_name 'John Doe'
logged_in_at Time.now
logged_out_at 0
end
end
At this point I know that the factories.rb file is being loaded (I tried with the moronic print-debugging). When I remove the user = FactoryGirl.build(:user) line from user_spec.rb I get no errors (and the normal RSpec feedback telling me there are no tests, but no errors). If you are interested, here's my model:
require 'digest/sha1'
module Bluereader
class User < ActiveRecord::Base
has_many :categories, :foreign_key => :user_id
has_many :news, :foreign_key => :user_id
has_many :settings, :foreign_key => :user_id
attr_reader :full_name
class << self
def login(username, password)
encrypted_password = Digest::SHA1.hexdigest(password)
if not User.exists?(:username => username, :encrypted_password => encrypted_password)
user_id = User.id_from_username(username)
update(user_id, :logged_in_at => Time.now, :logged_out_at => 0)
end
end
def logout
update(current_user.id, :logged_out_at => Time.now)
end
def validate_account(username, password, full_name)
if username.empty? or password.empty or full_name.empty?
return 'Please fill in all the fields.'
end
if User.exists?(:username => username)
return 'That username is already in use.'
end
unless username =~ /^\w+$/
return 'Username field should contain only letters, numbers and underscores.'
end
''
end
def create_account(username, password, full_name)
encrypted_password = Digest::SHA1.hexdigest(password)
User.create(:username => username,
:encrypted_password => encrypted_password,
:full_name => full_name,
:logged_in_at => Time.now,
:logged_out_at => 0)
end
def delete_account
current_user.destroy
end
private
def id_from_username(username)
user = where(:username => username).first
user.nil? ? 0 : user.id
end
def current_user
where(:logged_out_at => 0).first
end
end
end
end
SOLUTION
The problem was that the class User was in a module, here's the solution:
factory :user, class: Bluereader::User do
You need to require the rails environment in your spec helper file. Add the following to spec/spec_helper.rb:
require File.expand_path("../../config/environment", __FILE__)
Update
Even if you're not using Rails, you'll still need to require the models in your spec helper.
Taken from the bottom of the question
The problem was that the class User was in a module, here's the solution:
factory :user, class: Bluereader::User do
For anyone clumsy like me, you may have FactoryGirl in your code where you meant to have FactoryBot

rails 3.1.0 belongs_to ActiveResource no longer working

I am upgrading from rails 3.0.7 to 3.1 and am having trouble getting my tests to pass. The problem occurs when I try to use a stubbed active resource object in a factory.
#employee.rb
class Employee < ActiveResource::Base; end
#task.rb
class Task < ActiveRecord::Base
belongs_to :employee
end
#factories.rb
Factory.define :employee do |e|
e.name "name"
end
Factory.define :task do |t|
t.employee { Factory.stub(:employee) }
end
On the console and in the spec stubbing an employee works. Referencing the stubbed employee object in a new task gives the following error.
Factory.create( :task, :employee => Factory.stub(:employee) )
NoMethodError:
undefined method `[]' for #<Employee:0x007fc06b1c7798>
EDIT
This is not a factory girl issue. I get the same error if I do the following in the console.
Task.new( :employee => Employee.first )
It must be related to how belongs_to maps the id column.
I didn't like the monkey patch so I created a module that I will include at initialization to extend ActiveRecord
module BelongsToActiveResource
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def ar_belongs_to( name, options = {} )
class_eval %(
def #{name}
##{name} ||= #{options[:class_name] || name.to_s.classify }.find( #{options[:foreign_key] || name.to_s + "_id" } )
end
def #{name}=(obj)
##{name} ||= obj
self.#{ options[:foreign_key] || name.to_s + "_id" } = ##{name}.#{ options[:primary_key ] || 'id' }
end
)
end
end
end
ActiveRecord::Base.class_eval { include BelongsToActiveResource }
Then in each ActiveRecord model would look like:
#task.rb
class Task < ActiveRecord::Base
ar_belongs_to :employee
end
Hope this helps someone

ActiveRecord::Base Without Table

This came up a bit ago ( rails model attributes without corresponding column in db ) but it looks like the Rails plugin mentioned is not maintained ( http://agilewebdevelopment.com/plugins/activerecord_base_without_table ). Is there no way to do this with ActiveRecord as is?
If not, is there any way to get ActiveRecord validation rules without using ActiveRecord?
ActiveRecord wants the table to exist, of course.
This is an approach I have used in the past:
In app/models/tableless.rb
class Tableless < ActiveRecord::Base
def self.columns
#columns ||= [];
end
def self.column(name, sql_type = nil, default = nil, null = true)
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default,
sql_type.to_s, null)
end
# Override the save method to prevent exceptions.
def save(validate = true)
validate ? valid? : true
end
end
In app/models/foo.rb
class Foo < Tableless
column :bar, :string
validates_presence_of :bar
end
In script/console
Loading development environment (Rails 2.2.2)
>> foo = Foo.new
=> #<Foo bar: nil>
>> foo.valid?
=> false
>> foo.errors
=> #<ActiveRecord::Errors:0x235b270 #errors={"bar"=>["can't be blank"]}, #base=#<Foo bar: nil>>
Validations are simply a module within ActiveRecord. Have you tried mixing them into your non-ActiveRecord model?
class MyModel
include ActiveRecord::Validations
# ...
end
I figure the more answers the better since this is one of the first results in google when searching for "rails 3.1 models without tables"
I've implements the same thing without using ActiveRecord::Base while including the ActiveRecord::Validations
The main goal was to get everything working in formtastic, and below I've included a sample payment that will not get saved anywhere but still has the ability to be validated using the validations we all know and love.
class Payment
include ActiveModel::Validations
attr_accessor :cc_number, :payment_type, :exp_mm, :exp_yy, :card_security, :first_name, :last_name, :address_1, :address_2, :city, :state, :zip_code, :home_telephone, :email, :new_record
validates_presence_of :cc_number, :payment_type, :exp_mm, :exp_yy, :card_security, :first_name, :last_name, :address_1, :address_2, :city, :state
def initialize(options = {})
if options.blank?
new_record = true
else
new_record = false
end
options.each do |key, value|
method_object = self.method((key + "=").to_sym)
method_object.call(value)
end
end
def new_record?
return new_record
end
def to_key
end
def persisted?
return false
end
end
I hope this helps someone as I've spent a few hours trying to figure this out today.
UPDATE: For Rails 3 this can be done very easy. In Rails 3+ you can use the new ActiveModel module and its submodules. This should work now:
class Tableless
include ActiveModel::Validations
attr_accessor :name
validates_presence_of :name
end
For more info, you can check out the Railscast (or read about it on AsciiCasts) on the topic, as well as this blog post by Yehuda Katz.
OLD ANSWER FOLLOWS:
You may need to add this to the solution, proposed by John Topley in the previous comment:
class Tableless
class << self
def table_name
self.name.tableize
end
end
end
class Foo < Tableless; end
Foo.table_name # will return "foos"
This provides you with a "fake" table name, if you need one. Without this method, Foo::table_name will evaluate to "tablelesses".
Just an addition to the accepted answer:
Make your subclasses inherit the parent columns with:
class FakeAR < ActiveRecord::Base
def self.inherited(subclass)
subclass.instance_variable_set("#columns", columns)
super
end
def self.columns
#columns ||= []
end
def self.column(name, sql_type = nil, default = nil, null = true)
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
end
# Overrides save to prevent exceptions.
def save(validate = true)
validate ? valid? : true
end
end
This is a search form that presents an object called criteria that has a nested period object with beginning and end attributes.
The action in the controller is really simple yet it loads values from nested objects on the form and re-renders the same values with error messages if necessary.
Works on Rails 3.1.
The model:
class Criteria < ActiveRecord::Base
class << self
def column_defaults
{}
end
def column_names
[]
end
end # of class methods
attr_reader :period
def initialize values
values ||= {}
#period = Period.new values[:period] || {}
super values
end
def period_attributes
#period
end
def period_attributes= new_values
#period.attributes = new_values
end
end
In the controller:
def search
#criteria = Criteria.new params[:criteria]
end
In the helper:
def criteria_index_path ct, options = {}
url_for :action => :search
end
In the view:
<%= form_for #criteria do |form| %>
<%= form.fields_for :period do |prf| %>
<%= prf.text_field :beginning_as_text %>
<%= prf.text_field :end_as_text %>
<% end %>
<%= form.submit "Search" %>
<% end %>
Produces the HTML:
<form action="/admin/search" id="new_criteria" method="post">
<input id="criteria_period_attributes_beginning_as_text" name="criteria[period_attributes][beginning_as_text]" type="text">
<input id="criteria_period_attributes_end_as_text" name="criteria[period_attributes][end_as_text]" type="text">
Note: The action attribute provided by the helper and the nested attributes naming format that makes it so simple for the controller to load all the values at once
There is the activerecord-tableless gem. It's a gem to create tableless ActiveRecord models, so it has support for validations, associations, types. It supports Active Record 2.3, 3.0, 3.2
The recommended way to do it in Rails 3.x (using ActiveModel) has no support for associations nor types.

Resources