My simple Sqlite3 database is as follows:
CREATE TABLE balances(
balance zilch
);
My Ruby is as follows:
require('active_record')
ActiveRecord::Base.establish_connection(:database => "testbalance.db", :adapter => "sqlite3")
class Balance < ActiveRecord::Base
end
x = Balance.new
x.balance = 50
x.save
When I exit, and come back, and enter in the same Ruby again, at first, (before I runx.balance = 50) balance is nil. Why is this? Why isn't my DB saving?
If you enter the same code, then you're creating a new object again. No wonder its balance is nil.
To check that your object is saved, you can (for example) check Balance.count before and after record creation.
This is an old demo way of using Active Record and not very useful for production. It will get you started though. My code will make connections without sqlite3 gem required. I think that Active Record will include it if you use the :adapter hash entry. Of course you need it installed but it's not really needed in your code for Active Record. Just try it without that require to see. Then if you're still in doubt, un-install the gem just for fun. There are more Active Record namespaces and methods you should try especially ones that check to see if the database already exists. Then by pass the creation of one.
Here's some sample code from the book Metaprogramming Ruby.
#---
# Excerpted from "Metaprogramming Ruby",
# published by The Pragmatic Bookshelf.
# Copyrights apply to this code. It may not be used to create training material,
# courses, books, articles, and the like. Contact us if you are in doubt.
# We make no guarantees that this code is fit for any purpose.
# Visit http://www.pragmaticprogrammer.com/titles/ppmetr2 for more book information.
#---
# Create a new database each time
File.delete 'dbfile' if File.exist? 'dbfile'
require 'active_record'
ActiveRecord::Base.establish_connection :adapter => "sqlite3",
:database => "dbfile.sqlite3"
# Initialize the database schema
ActiveRecord::Base.connection.create_table :ducks do |t|
t.string :name
end
class Duck < ActiveRecord::Base
validate do
errors.add(:base, "Illegal duck name.") unless name[0] == 'D'
end
end
my_duck = Duck.new
my_duck.name = "Donald"
my_duck.valid? # => true
my_duck.save!
require_relative '../test/assertions'
assert my_duck.valid?
bad_duck = Duck.new(:name => "Ronald")
assert !bad_duck.valid?
duck_from_database = Duck.first
duck_from_database.name # => "Donald"
assert_equals "Donald", duck_from_database.name
duck_from_database.delete
File.delete 'dbfile' if File.exist? 'dbfile'
This code deletes the db file after usage and that's not very good persistence either. But you get the idea as it's just for testing assertions. You could try that to be sure as you change balances.
Do you want the rest of the code? https://pragprog.com/book/ppmetr/metaprogramming-ruby
Am I training you or am I the like? Moderators delete this if I'm wrong here please. I don't want to set a bad example.
Related
I have been tasked with creating a Ruby API that retrieves youtube URL's. However, I am not sure of the proper way to create an 'API'... I did the following code below as a Sinatra server that serves up JSON, but what exactly would be the definition of an API and would this qualify as one? If this is not an API, how can I make in an API? Thanks in advance.
require 'open-uri'
require 'json'
require 'sinatra'
# get user input
puts "Please enter a search (seperate words by commas):"
search_input = gets.chomp
puts
puts "Performing search on YOUTUBE ... go to '/videos' API endpoint to see the results and use the output"
puts
# define query parameters
api_key = 'my_key_here'
search_url = 'https://www.googleapis.com/youtube/v3/search'
params = {
part: 'snippet',
q: search_input,
type: 'video',
videoCaption: 'closedCaption',
key: api_key
}
# use search_url and query parameters to construct a url, then open and parse the result
uri = URI.parse(search_url)
uri.query = URI.encode_www_form(params)
result = JSON.parse(open(uri).read)
# class to define attributes of each video and format into eventual json
class Video
attr_accessor :title, :description, :url
def initialize
#title = nil
#description = nil
#url = nil
end
def to_hash
{
'title' => #title,
'description' => #description,
'url' => #url
}
end
def to_json
self.to_hash.to_json
end
end
# create an array with top 3 search results
results_array = []
result["items"].take(3).each do |video|
#video = Video.new
#video.title = video["snippet"]["title"]
#video.description = video["snippet"]["description"]
#video.url = video["snippet"]["thumbnails"]["default"]["url"]
results_array << #video.to_json.gsub!(/\"/, '\'')
end
# define the API endpoint
get '/videos' do
results_array.to_json
end
An "API = Application Program Interface" is, simply, something that another program can reliably use to get a job done, without having to busy its little head about exactly how the job is done.
Perhaps the simplest thing to do now, if possible, is to go back to the person who "tasked" you with this task, and to ask him/her, "well, what do you have in mind?" The best API that you can design, in this case, will be the one that is most convenient for the people (who are writing the programs which ...) will actually have to use it. "Don't guess. Ask!"
A very common strategy for an API, in a language like Ruby, is to define a class which represents "this application's connection to this service." Anyone who wants to use the API does so by calling some function which will return a new instance of this class. Thereafter, the program uses this object to issue and handle requests.
The requests, also, are objects. To issue a request, you first ask the API-connection object to give you a new request-object. You then fill-out the request with whatever particulars, then tell the request object to "go!" At some point in the future, and by some appropriate means (such as a callback ...) the request-object informs you that it succeeded or that it failed.
"A whole lot of voodoo-magic might have taken place," between the request object and the connection object which spawned it, but the client does not have to care. And that, most of all, is the objective of any API. "It Just Works.™"
I think they want you to create a third-party library. Imagine you are schizophrenic for a while.
Joe wants to build a Sinatra application to list some YouTube videos, but he is lazy and he does not want to do the dirty work, he just wants to drop something in, give it some credentials, ask for urls and use them, finito.
Joe asks Bob to implement it for him and he gives him his requirements: "Bob, I need YouTube library. I need it to do:"
# Please note that I don't know how YouTube API works, just guessing.
client = YouTube.new(api_key: 'hola')
video_urls = client.videos # => ['https://...', 'https://...', ...]
And Bob says "OK." end spends a day in his interactive console.
So first, you should figure out how you are going to use your not-yet-existing lib, if you can – sometimes you just don't know yet.
Next, build that library based on the requirements, then drop it in your Sinatra app and you're done. Does that help?
I'm reading a book that's making a Twitter clone with Sinatra in order to improve my knowledge of Ruby. I'm puzzled by the author's use of
User.first(:nickname => params[:recipient])
which he uses in several locations throughout the code, as in the following example.
post '/message/send' do
recipient = User.first(:nickname => params[:recipient])
Status.create(:text => params[:message], :user => User.
get(session[:userid]), :recipient => recipient)
redirect '/messages/sent'
end
What exactly is 'first' adding to this method. For example, is it searching for the first user with the nickname passed in as the parameter :recipient? In other words, is it equivalent to 'find'?
I should add that it puzzles me also because the nicknames are supposed to be unique, so there's no reason why it would need to search for the 'first' if that's indeed what it's doing.
Update
The author is using DataMapper for the ORM
Ok, 'first' is a datamapper method that 'finds'. From the docs
zoo = Zoo.first(:name => 'Metro') # first matching record with the name 'Metro'
I have read through the Web Services site at http://developer.rallydev.com/help/
The basic issue I have is that I am trying to update custom created fields in Rally from a Ruby script and I do not know the format to use. The Rally Devs said this was possible and directed me to post here as they do not support users with such things.
I am wondering if anyone else has been able to do this. I can get the defect, but the debug info has not given me any clues as to where these custom fields may be lurking. Thanks in advance for your help and please let me know if you need any additional information. The simple code I have right now is this:
#!/usr/bin/ruby
require 'rubygems'
require 'rally_rest_api'
defect = "DE677"
logger = Logger.new("debug-rally.txt")
logger.level = Logger::DEBUG
rally = RallyRestAPI.new(:username => "hidden",
:password => "hidden",
:logger => logger,
:version => 1.34)
result = rally.find(:defect) { equal :formattedid, defect }
if result.page_length == 0
puts "The defect "+defect+" was not found"
elsif result.page_length == 1
puts "Found it"
res_array = result.results
thedefect = res_array.at(0)
puts thedefect.state
puts thedefect.requirement.defects
else
puts "Returned more than one result"
puts result.page_length
res_array = result.results
for i in res_array
puts i
end
end
EDIT:It was actually staring me right in the face. When I checked the debug log again they were in the xml. For instance in the UI there was a custom field called fu and in the resulting xml it was there as bar.
There is a display name and a name property when you create it. In your example my guess is fu is your display name and bar is the name.
I've come to seek your collective wisdom.
My goal, an overview:
In order to better manage computers for various clients, I'm attempting to extend Puppet's Dashboard. It's a Rails 2 application, and I'm trying to extend it with a Rails 3 application I'm writing. There are a few problems that make Dashboard less than perfect for my needs, but the solutions are simple. I'm going to focus on one, because I feel that the answer to this question will help me figure the rest out. I've been looking into solutions that don't alter the dashboard code at all, because I'm not the maintainer, and don't want to make a future mess.
I thought a lot about how to do this best. I thought about plugging directly into the database but I got cold feet after doing a little googling. It appears that setting up a second database connection isn't that difficult, the thing I don't like is altering another application's database while it's running. Please say something if I'm passing up a perfectly reasonable option, based on superstition.
There were a few other ideas, but the one that I started in on finally, and had marginal success with was accessing Dashboard's database via REST. It's built in, why not use it? Well, I was able to manipulate a couple of the tables, but not the one that I wanted to. So there are three tables to be aware of in this situation.
nodes (basically computers)
node_groups (the groups you can put computers in)
node_group_memberships (the join table that relates 1 and 2 to each other)
I can add and remove both nodes, and node_groups, but I want to be able to create a connection between the two as well. In order to create a new user, I have an ActiveResource model set up that looks like this:
class PuppetNode < ActiveResource::Base
self.site = "http://127.0.0.1:4000/"
self.element_name = "node"
attr_accessor :grouped
end
I'm then free to create new nodes, or grab info from the nodes table via the console. It might look something like this:
PuppetNode.create(:column_name => "and so on")
The same goes for node_groups, and I can even create a Rails 3 model that doesn't wig out for node_group_memberships, but I can't create anything in that table. I can see if I look at the Rails 2 node_group_membership controller (by the good folks over at Puppet Labs), that there is a create method
class NodeGroupMembershipsController < InheritedResources::Base
respond_to :json
before_filter :raise_if_enable_read_only_mode, :only => [:new, :edit, :create, :update, :destroy]
before_filter :standardize_post_data, :only => [:create]
def create
create! do |success, failure|
success.json { render :text => #node_group_membership.to_json, :content_type => 'application/json', :status => 201 }
failure.json { render :text => {}.to_json, :content_type => 'application/json', :status => 422 }
end
end
# we want: {node_group_membership => {node_id => <id>, node_group_id => <id>}
# allow and convert: {node_name => <name>, group_name => <name>}
def standardize_post_data
unless params[:node_group_membership]
params[:node_group_membership] = {}
node = Node.find_by_name(params[:node_name])
group = NodeGroup.find_by_name(params[:group_name])
params[:node_group_membership][:node_id] = (node && node.id)
params[:node_group_membership][:node_group_id] = (group && group.id)
end
end
end
But for whatever reason it chokes out every time I try to create an association with something like this
irb(main):005:0> PuppetNodeGroupMembership.create(:node_id => 20, :node_group_id => 5)
=> #<PuppetNodeGroupMembership:0x007fb3150af878 #attributes={"node_id"=>20, "node_group_id"=>5}, #prefix_options={}, #persisted=false, #remote_errors=#<ActiveResource::ResourceInvalid: Failed. Response code = 422. Response message = .>, #validation_context=nil, #errors=#<ActiveResource::Errors:0x007fb3150af4e0 #base=#<PuppetNodeGroupMembership:0x007fb3150af878 ...>, #messages={}>>
Any advice would be much appreciated, I've already put a solid 8 miserable hours into trying to figure it out. Thanks!
For better or for worse one thing that does work is connecting to a second database with the same Rails application. I'm leaving this marked as "An Answer" for now, but not "The Answer".
This is the resource that I found that helped me along:
http://www.rubynaut.net/articles/2008/05/31/how-to-access-multiple-database-in-rails.html
n the .net world, my specs would follow the Arrange, Act, Assert pattern. I'm having trouble replicating that in rspec, because there doesn't appear to be an ability to selectively verify your mocks after the SUT has taken it's action. That, coupled with the fact that EVERY expectation is evaluated at the end of each 'It' block, is causing me to repeat myself in a lot of my specs.
Here's an example of what I'm talking about:
describe 'AmazonImporter' do
before(:each) do
Kernel.**stubs**(:sleep).with(1)
end
# iterates through the amazon categories, and for each one, loads ideas with
# the right response group, upserting ideas as it goes
# then goes through, and fleshes out all of the ideas that only have asins.
describe "find_new_ideas" do
before(:all) do
#xml = File.open(File.expand_path('../amazon_ideas_in_category.xml', __FILE__), 'r') {|f| f.read }
end
before(:each) do
#category = AmazonCategory.new(:name => "name", :amazon_id => 1036682)
#response = Amazon::Ecs::Response.new(#xml)
#response_group = "MostGifted"
#asin = 'B002EL2WQI'
#request_hash = {:operation => "BrowseNodeLookup", :browse_node_id => #category.amazon_id,
:response_group => #response_group}
Amazon::Ecs.**expects**(:send_request).with(has_entries(#request_hash)).returns(#response)
GiftIdea.expects(:first).with(has_entries({:site_key => #asin})).returns(nil)
GiftIdea.any_instance.expects(:save)
end
it "sleeps for 1 second after each amazon request" do
Kernel.**expects**(:sleep).with(1)
AmazonImporter.new.find_new_ideas(#category, #response_group)
end
it "loads the ideas for the given response group from amazon" do
Amazon::Ecs.**expects**(:send_request).
with(has_entries(#request_hash)).
returns(#response)
**AmazonImporter.new.find_new_ideas(#category, #response_group)**
end
it "tries to load those ideas from repository" do
GiftIdea.expects(:first).with(has_entries({:site_key => #asin}))
**AmazonImporter.new.find_new_ideas(#category, #response_group)**
end
In this partial example, I'm testing the find_new_ideas method. But I have to call it for each spec (the full spec has 9 assertion blocks). I further have to duplicate the mock setup so that it's stubbed in the before block, but individually expected in the it/assertion block. I'm duplicating or nearly duplicating a ton of code here. I think it's even worse than the highlighting indicates, because a lot of those globals are only defined separately so that they can be consumed by an 'expects' test later on. Is there a better way I'm not seeing yet?
(SUT = System Under Test. Not sure if that's what everyone calls it, or just alt.net folks)
You can use shared example groups to reduce duplication:
shared_examples_for "any pizza" do
it "tastes really good" do
#pizza.should taste_really_good
end
it "is available by the slice" do
#pizza.should be_available_by_the_slice
end
end
describe "New York style thin crust pizza" do
before(:each) do
#pizza = Pizza.new(:region => 'New York' , :style => 'thin crust' )
end
it_behaves_like "any pizza"
it "has a really great sauce" do
#pizza.should have_a_really_great_sauce
end
end
Another technique is to use macros, which is handy if you need similar specs in different classes.
Note: the example above is borrowed from The RSpec Book, Chapter 12.
you can separate them using "context" if that helps...
https://github.com/dchelimsky/rspec/wiki/faq