I'm trying to create a simple wine web app with Sinatra. The keys within my Wine model are "vintner", "vintage", and "varietal". Vintage is an integer. I also have a Note model for users to add in notes (currently separating by commas, will plan to get more robust later...).
Here is my POST action within my WineController:
post '/wines' do
if params[:wine] == ""
erb :'wines/new'
else
#wine = current_user.wines.new(params[:wine])
#wines = current_user.wines
if #wines.detect{ |wine| wine.vintner.downcase ==
#wine.vintner.downcase && wine.varietal.downcase ==
#wine.varietal.downcase && wine.vintage == #wine.vintage }
flash[:message] = "That wine is already in your cellar! Add another."
erb :'/wines/new'
elsif !params[:note][:name].empty?
params[:note][:name].split(", ").each{ |user_note| #wine.notes <<
Note.find_or_create_by(:name => user_note) }
end
end
#wine.save
redirect to "/wines"
end
What I'm trying to accomplish is to say "if there is already a wine with that vintner, varietal, and vintage, don't create it and redirect back to the 'new' view with said message. Otherwise, add the notes to the that wine instance, save, and redirect to '/wines/index'".
Instead, though, the wine saves (the notes are not being saved, though) and I get redirected to '/wines/index' with said message. So, that's weird.
My main question is, how can I detect (using detect or any other method) based on three or more criteria. Also, if anyone has any insight into what I'm doing wrong with my notes, I'd love to hear! Thank you!!
As it currently is written the lines
#wine.save
redirect to "/wines"
are outside all the conditionals at the very bottom of the block, so that code will run, even if the condition params[:wine] == "" is met, and in that case it will error out because #wine doesn't get set.
Try moving that code into maybe the elsif !params[:note][:name].empty? branch and then it should only run when you need to create a new wine.
Related
I've written a filter and use its register-function to load an external CSV-file and fill a bunch of hash-tables. The filter-function then accesses the hash-tables and adds fields to the event. While that's working nicely, the downside is that it only loads once and I'd need to restart logstash to trigger the reload after a change in the CSV-file. Maybe I should add that the filter is currently consuming events coming from three different file inputs.
Writing an input doesn't seem to solve it as the input is not tied to the filter in some way. Therefore, my plan is to somehow reload the CSV-file every few hours or at a particular time and somehow block the entire filter during that, i.e. pause incoming events. That sounds like a weird thing to do and I'm not sure whether or not logstash is actually meant to be used like this.
I'm a newbie regarding Ruby and actually I'm quite amazed that the filter is working this nice. As Google let me down on the entire issue I'm hoping that anyone on here has experience with this, can post a link to an example or can point me to another way of solving this.
For educational purposes I looked into the source of logstash and noticed that I could actually understand what's going on and things are much less complicated than I had thought.
There is a function filterworker in pipeline.rb and a class filterworker and I don't know which one is actually used, but my findings seem to be true for both.
Basically all filters seem to run in one thread in case it's not configured otherwise. This means that I can reload the file anywhere in the filter-function and the entire processing for all filters is paused (input and output might still do something, but that's handled by the queue for the events holding maximum 20 entries).
Therefore, this seems to do it for me:
public
def register
#config_files_read_timestamps = {}
read_config_files
end # def register
def filter(event)
# return nothing unless there's an actual filter event
return unless filter?(event)
read_config_files
:
# filter_matched should go in the last line of our successful code
filter_matched(event)
end # def filter
private
def read_config_files
read_marker_file
:
end
def check_for_changed_file?(filename)
mtime = File.mtime(filename)
#config_files_read_timestamps[filename] ||= Time.at(0)
if #config_files_read_timestamps[filename] < mtime
#config_files_read_timestamps[filename] = mtime
return true
end
end
def read_marker_file
if !check_for_changed_file?("markers.txt")
return
end
:
end
Obviously I don't need a separate thread for the parsing. It would become necessary if I plan to start the reload at a specific time. In that case I'd have to join the thread and then continue with event handling.
Let me know if there could be improvements...
Was following the Depot application from Agile Web Development with Rails.
There was a method I got confused. I thought I understood it until I tried it in irb. So here's the method:
def add_product(product_id)
current_item = line_items.find_by_product_id(product_id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(product_id: product_id)
end
current_item
end
From what I understood, It's just a method that will first find a record in LineItems with a product ID of an give input (let's say it's 10). Then it will store it in current_item variable. The condition says 'If the product id was found, add 1 to quantity else create a new instance of that record with the product id equals to 10'
Here's the snapshot of my rails console
As you can see, product id of 10 in LineItem is not found. But on my condition, it goes against everything that I believe until now. Could someone shed a light on this?
Looks like line is an empty collection (ActiveRecord::Relation to be exact) and so it's something in Ruby and not nil. That's why it's returning true when you're calling if line and executing puts 'I'm true and happy'.The reason it's an ActiveRecord::Relation is because you're using the where query.
In the Depot application they're making the query by calling line_items.find_by_product_id(product_id) which is different. It finds the first record matching the condition.
Check out the Rails guides here for more info - http://guides.rubyonrails.org/active_record_querying.html (section 15)
PS Looks like that type of query is deprecated in Rails 4 so not sure what version of Agile Web Development with Rails you're looking at.
I'm testing a nightmarish website that in most situations sticks all the important stuff in an iframe.
However, there are other common situations where the system will, annoyingly, open a page in a new tab, but not wrapped in the iframe.
I'm trying to figure out a conditional method that will check for the existence of the iframe and use it, otherwise not.
Here's what I've come up with, so far:
# The browser object...
#br = Watir::Browser.new
"frm" is the conditional method I'm trying to get working...
# Just an example element definition...
def click_my_button
#br.frm.button(id: "button").click
end
I define it in Watir's Container module, like so:
module Watir
module Container
def frm
if frame(id: "iframeportlet").exist?
frame(id: "iframeportlet")
else
# This is the part that I can't figure out.
end
end
end
end
That works fine when the iframe is there, but not surprisingly I get a NilClass error when it's not.
So, my question is: what can go into the else clause to make it work? More broadly, is there perhaps a better way to accomplish this? As you can imagine, I really want to avoid having to define every element in the web site twice.
I figured it out, and it's quite simple. The frm method's else clause just needs a "self"...
else
self
end
That's it. I'd love to know if there are any hidden pitfalls with this approach, though.
I'm automating a site that has a page with a list of options selected by a radio button. When selecting one of the radios, a text field and a select list are presented.
I created a file (test_contracting.rb) that is the one through which I execute the test (ruby test_contracting.rb) and some other classes to represent my page.
On my class ContractPage, I have the following element declaration:
checkbox(:option_sub_domain, :id => "option_sub_domain")
text_field(:domain, :id => "domain_text")
select_list(:tld, :id => "domain_tld")
I've created in the ContractPage a method that sets the configuration of the domain like this:
def configure_domain(config={})
check_option_sub_domain
domain = config[:domain]
tld = config[:tld]
end
When I call the method configure_domain from the test_contracting.rb, it selects the radio button, but it doesn't fill the field with the values. The params are getting into the method correctly. I've checked it using "puts". Even if I change the params to a general string like "bla" it doesnt work. The annoying point is that if on test_contracting.rb I call the exact same components, it works.
my_page_instance = ContractPage.new(browser)
my_page_instance.domain = "bla"
my_page_instance.tld = ".com"
What I found to work was to in the configure_domain method, implement the following:
domain_element.value = config[:domain]
tld_element.send_keys config[:locaweb_domain]
Then it worked.
The documentation for the PageObjects module that I'm using as reference can be found here: http://rubydoc.info/github/cheezy/page-object/master/PageObject/Accessors#select_list-instance_method
Do you guys have any explation on why the method auto generated by the pageobject to set the value of the object didnt work in this scope/context ?
By the way, a friend tried the same thing with Java and it failed as well.
In ruby all equals methods (methods that end with the = sign) need to have a receiver. Let me show you some code that will demonstrate why. Here is the code that sets a local variable to a value:
domain = "blah"
and here is the code that calls the domain= method:
domain = "blah"
In order for ruby to know that you are calling a method instead of setting a local variable you need to add a receiver. Simply change your method above to this and it will work:
def configure_domain(config={})
check_option_sub_domain
self.domain = config[:domain]
self.tld = config[:tld]
end
I'm pretty new to this world of Selenium and page objects but maybe one of my very recent discoveries might help you.
I found that that assignment methods for the select_list fields only worked for me once I started using "self" in front. This is what I have used to access it within my page object code. e.g., self.my_select_list="my select list value"
Another note - The send_keys workaround you mention is clever and might do the trick for a number of uses, but in my case the select list values are variable and may have several options starting with the same letter.
I hope something in here is useful to you.
UPDATE (Jan 3/12)
On diving further into the actual Ruby code for the page object I discovered that the select_list set is also using send_keys, so in actuality I still have the same limitation here as the one I noted using the send_keys workaround directly. sigh So much to learn, so little time!
I'd like to know about idioms or best practices for testing a multi-step workflow using rspec.
Let's take as an example a "shopping cart" system, where the buying process might be
when user submits to basket and we are not using https, redirect to https
when user submits to basket and we are using https and there is no cookie, create and display a new basket and send back a cookie
when user submits to basket and we are using https and there is a valid cookie and the new item is for a different product than the first item, add a line to the basket and display both lines
when user submits to basket and we are using https and there is a valid cookie and the new item is for the same product as a previous one, increment that basket line's quantity and display both lines
when user clicks 'checkout' on the basket page and is using https and there is a cookie and the basket is non-empty and ...
...
I've read http://eggsonbread.com/2010/03/28/my-rspec-best-practices-and-tips/ which advises i.a that each "it block" should contain only one assertion: instead of doing the computation and then testing several attributes in the same block, use a "before" inside a context to create (or retrieve) the object under test and assign it to #some_instance_variable, then write each attribute test as a separate block. That helps a little, but in a case such as outlined above where testing step n requires doing all the setup for steps [1..n-1] I find myself either duplicating setup code (obviously not good) or creating lots of helper functions with increasingly unwieldy names (def create_basket_with_three_lines_and_two_products) and calling them consecutively in each step's before block.
Any tips on how to do this less verbosely/tediously? I appreciate the general principle behind the idea that each example should not depend on state left behind by previous examples, but when you're testing a multi-step process and things can go wrong at any step, setting up the context for each step is inevitably going to require rerunning all the setup for the previous n steps, so ...
Here's one possible approach -- define an object that creates the necessary state for each step and pass it forward for each successive one. Basically you need to mock/stub the method calls for all the setup conditions:
class MultiStep
def initialize(context)
#context = context
end
def init_vars
#cut = #context.instance_variable_get(:#cut)
end
def setup(step)
init_vars
method(step).call
end
def step1
#cut.stub(:foo).and_return("bar")
end
def step2
step1
#cut.stub(:foo_bar).and_return("baz_baz")
end
end
class Cut # Class Under Test
def foo
"foo"
end
def foo_bar
"foo_bar"
end
end
describe "multiple steps" do
before(:each) do
#multi_stepper = MultiStep.new(self)
#cut = Cut.new
end
it "should setup step1" do
#multi_stepper.setup(:step1)
#cut.foo.should == "bar"
#cut.foo_bar.should == "foo_bar"
end
it "should setup step2" do
#multi_stepper.setup(:step2)
#cut.foo.should == "bar"
#cut.foo_bar.should == "baz_baz"
end
end
Certainly too late for OP, but this could be handy for others - the rspec-steps gem seems to be built for this exact situation: https://github.com/LRDesign/rspec-steps
It might be worthwhile to look at https://github.com/railsware/rspec-example_steps and https://github.com/jimweirich/rspec-given as well. I settled on rspec-steps, but I was in a rush and these other options might actually be better for all I know.