How to create instance variables with iterator - ruby

I have a lab through school where I need to create a form that takes in basketball team attributes, team name, coach, point guard etc., and want to know if there is any way to dynamically create instance variables and symbols using an iterator of sorts instead of hard coding them?
Here is the hard-coded version of what I mean:
post "/team" do
#name = params["name"]
#coach = params["coach"]
#pg = params["pg"]
#sg = params["sg"]
#pf = params["pf"]
#sf = params["sf"]
#c = params["c"]
erb :team
end
I want to use something similar to this:
post '/team' do
params.each do |parameter|
#[parameter] = params["#{parameter}"]
end
erb :team
end
When I run the above code I receive a unexpected end-of-input syntax error.

Try to use instance_variable_set,
something like this:
post '/team' do
params.each do |key, value|
self.instance_variable_set("##{key}", value)
end
erb :team
end

Related

Nil object in Ruby

Could anyone advise me what is wrong on this script? I am a complete beginner with ruby, but I still do not understand why this object is empty in the dump. Thank you for your advice.
require 'sinatra'
class Person
def initialize(first_name, last_name, age, country)
#per_first_name = first_name
#per_last_name = last_name
#per_age = age
#per_country = country
end
def get_basic_info()
puts Array.[](#per_first_name, #per_last_name, #per_age, #per_country)
end
end
get '/basicInfo' do
xavier = Person.new('Tada', 'Bada', 25, 'CR')
xavier.inspect
end
It doesn't seem to be an error, i think you are getting a # in your page when going to http://localhost:4567/basicInfo, and that's the expected behavior since your are calling inspect on your new created Person object.
I assume that you want to display get_basic_info instead, if so, you need to do a couple of changes:
First, remove puts from get_basic_info since puts will print in console, not on your page:
def get_basic_info()
Array.[](#per_first_name, #per_last_name, #per_age, #per_country)
end
Second, call your method before calling inspect, so you get the array of basic info before inspecting it:
get '/basicInfo' do
xavier = Person.new('Tada', 'Bada', 25, 'CR')
xavier.get_basic_info.inspect
end

Fetching array of data from DB using Rails 3

I want to access multiple columns using Rails 3.But it gave me the following error.
Error:
ArgumentError (wrong number of arguments (2 for 1)):
app/controllers/payments_controller.rb:13:in `check_type'
Check my below code.
payment_controller.rb:
class PaymentsController < ApplicationController
def payment
#payment=Vendor.new
respond_to do |format|
format.html
format.js
end
end
def check_type
if params[:commit]=="submit"
#vendor_type=PaymentVendor.where(:v_name => params[:v_name]).pluck(:type ,:Receipt_No)
#vendor_type.each do |vendor|
end
else
#v_name=Vendor.where(:s_catagory => params[:payment][:s_catagory] ).pluck(:v_name)
end
end
end
Actually i want to retrive data like below format.
#vendor_type=["Receipt_no":"type","Receipt_no":"type",.....]
Once these data will appear,I need how to access row values according to Receipt_No.Please help me to resolve this error.
Thanks to ActiveRecord >= 4 . pluck accepts multiple arguments so in
Rails 4: Your query will work
#vendor_type=PaymentVendor.where(:v_name => params[:v_name]).pluck(:type ,:Receipt_No)
Now as you are using Rails 3 which doesn't support multiple arguments to pluck then we can extend ActiveRecord::Relation itself like this:
put your file under config/initializers
# pluck_all.rb
module ActiveRecord
class Relation
def pluck_all(*args)
args.map! do |column_name|
if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
"#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
else
column_name.to_s
end
end
relation = clone
relation.select_values = args
klass.connection.select_all(relation.arel).map! do |attributes|
initialized_attributes = klass.initialize_attributes(attributes)
attributes.each do |key, attribute|
attributes[key] = klass.type_cast_attribute(key, initialized_attributes)
end
end
end
end
end
Now in your controller you can pass multiple arguments to pluck like this:
# payment_controller.rb:
#vendor_type=PaymentVendor.where(:v_name => params[:v_name]).pluck_all(:type ,:Receipt_No)
Now you can use pluck_all in whole app. Hope this helps ;)
EDIT:
Try below code if plcuk_all not worked:
#vendor_type = PaymentVendor.where(:v_name => params[:v_name]).map{|v|[v.type ,v.Receipt_No]}
Reference for more info: http://meltingice.net/2013/06/11/pluck-multiple-columns-rails/
Your pluck(:type ,:Receipt_No) looks wrong,
pluck have only one argument.
Also your type of data #vendor_type is wrong, Array don't have key, value pair.
Use map like this,
#vendor_type=PaymentVendor.where(:v_name => params[:v_name]).map { |i| [i.Receipt_No] }
In terms of making a rails 3 method that behaves the same as the Rails 4 pluck with multiple columns. This outputs a similar array (rather than a hashed key value collection). This should save a bit of pain if you ever come to upgrade and want to clean up the code.
See this tutorial which outlines a similar method that outputs a hash.
config/initializers/pluck_all.rb
module ActiveRecord
class Relation
def pluck_all(*args)
args.map! do |column_name|
if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
"#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
else
column_name.to_s
end
end
relation = clone
relation.select_values = args
klass.connection.select_all(relation.arel).map! do |attributes|
initialized_attributes = klass.initialize_attributes(attributes)
attributes.map do |key, attribute|
klass.type_cast_attribute(key, initialized_attributes)
end
end
end
end
end
Standing on the shoulders of giants and all

Variable URL with Instance Variables

I know I'm being an idiot here, but I can't think of how this is done. I am creating an app with certain interests and am using a a Wikipedia scrape set up using Nokogiri. I have two inputs: Title and Wikipedia, but want to fill Summary and Content in the data model using the scrape. I want to use the Wikipedia attribute as a variable in a url within a method, but keep getting the error dynamic constant assignment PAGE_URL = "http://en.wikipedia.org/w/i....
I thought that the methods should go in the model, with reference to them in the Create definition under the controller, but this doesn't seem to work.
EDIT
I've just tried taking the constants out of the methods as suggested, but I am still getting a dynamic constant assignment error. My model currently looks like this:
PAGE_URL1 = "http://en.wikipedia.org/w/index.php?title="
PAGE_URL2 = "&printable=yes"
def get_PAGE_URL
PAGE_URL = PAGE_URL1 + self.wikipedia + PAGE_URL2
end
def get_page
page = Nokogiri::HTML(open(PAGE_URL))
end
def get_summary
get_PAGE_URL
self.summary = page.css("p")[0].text
end
def get_full_page
get_PAGE_URL
puts page.css('div#content.mw-body div#bodyContent div#mw-content-text.mw-content-ltr p').each do |p|
self.content = puts p.text
end
end
Constants can't go inside of methods, they must be defined inside of the class' direct scope.
Edit:
For example:
class WikiScraper
PAGE_URL = "http://www.wikipedia.org/"
def scrape
page_num = '5'
my_url = PAGE_URL + page_num
end
end

How do I access a variable inside the method I'm calling in a block I'm passing to it?

I'm writing a wrapper for an XML API using Nokogiri to build the XML for submission.
In order to keep my code DRY, I'm using custom blocks for the first time and just getting to grips with how to pass variables back and forth and how that works.
What I'm doing at the moment is this:
# Generic action
def action(xml, action_title, test=false)
xml.request do
xml.login do
xml.username("my_user")
xml.password("my_pass")
end
xml.action(action_title)
xml.params do
yield
end
end
end
# Specific action
def get_users(city = "", gender = "")
build = Nokogiri::XML::Builder.new do |xml|
action(xml, "getusers") do
xml.city(city) unless city.blank?
xml.gender(gender) unless gender.blank?
end
end
do_stuff_to(build)
end
Ideally, I'd like to the specific action method to look like this:
def get_users(city = "", gender = "")
action("getusers") do |xml|
xml.city(city) unless city.blank?
xml.gender(gender) unless gender.blank?
end
end
In doing so, I'd want the other logic currently in the specific action method to be moved to the generic action method with the generic action method returning the results of do_stuff_to(build).
What I'm struggling with is how to pass the xml object from action() back to get_users(). What should action() look like in order to achieve this?
Turns out this was quite simple. The action method needs to be changed so it looks like this:
def action(action_title)
build = Nokogiri::XML::Builder.new do |xml|
xml.request do
xml.login do
xml.username("my_user")
xml.password("my_pass")
end
xml.action(action_title)
xml.params do
yield xml
end
end
end
do_stuff_to(build)
end
That meant the specific action method could be called like this to the same effect:
def get_users(city = "", gender = "")
action("getusers") do |xml|
xml.city(city) unless city.blank?
xml.gender(gender) unless gender.blank?
end
end

Static local variables for methods in Ruby?

I have this:
def valid_attributes
{ :email => "some_#{rand(9999)}#thing.com" }
end
For Rspec testing right? But I would like to do something like this:
def valid_attributes
static user_id = 0
user_id += 1
{ :email => "some_#{user_id}#thing.com" }
end
I don't want user_id to be accessible from anywhere but that method,
is this possible with Ruby?
This is a closure case. Try this
lambda {
user_id = 0
self.class.send(:define_method, :valid_attributes) do
user_id += 1
{ :email => "some_#{user_id}#thing.com" }
end
}.call
Wrapping everything in lambda allows the variables defined within lambda to only exist in the scope. You can add other methods also. Good luck!
This answer is a little larger in scope than your question, but I think it gets at the root of what you're trying to do, and will be the easiest and most maintainable.
I think what you're really looking for here is factories. Try using something like factory_girl, which will make a lot of testing much easier.
First, you'd set up a factory to create whatever type of object it is you're testing, and use a sequence for the email attribute:
FactoryGirl.define do
factory :model do
sequence(:email) {|n| "person#{n}#example.com" }
# include whatever else is required to make your model valid
end
end
Then, when you need valid attributes, you can use
Factory.attributes_for(:model)
You can also use Factory.create and Factory.build to create saved and unsaved instances of the model.
There's explanation of a lot more of the features in the getting started document, as well as instructions on how to add factories to your project.
You can use a closure:
def validator_factory
user_id = 0
lambda do
user_id += 1
{ :email => "some_#{user_id}#thing.com" }
end
end
valid_attributes = validator_factory
valid_attributes.call #=> {:email=>"some_1#thing.com"}
valid_attributes.call #=> {:email=>"some_2#thing.com"}
This way user_id won't be accessible outside.
I'd use an instance variable:
def valid_attributes
#user_id ||= 0
#user_id += 1
{ :email => "some_#{#user_id}#thing.com" }
end
The only variables Ruby has are local variables, instance variables, class variables and global variables. None of them fit what you're after.
What you probably need is a singleton that stores the user_id, and gives you a new ID number each time. Otherwise, your code won't be thread-safe.

Resources