How to read file in Rails style - ruby-on-rails

I have some data stored as an XML file. I put it into a directory I've created, app/data/myxml.xml.
Now I want to parse it using Nokogiri. To locate the file I am referencing an absolute path:
#doc = Nokogiri::XML(open("/home/me/webA/myrailsproject/app/data/myxml.xml"))
The absolute path definitely make the code ugly. Is there a shorter, cleaner way to reference the file? Such as:
#doc = Nokogiri::XML(open("myxml"))

The current directory in a Rails is the application root, so you could just do
#doc = Nokogiri::XML(open("data/myxml.xml"))
Or if you want to be sure, you can use the RAILS_ROOT constant -
#doc = Nokogiri::XML(open("#{RAILS_ROOT}/data/myxml.xml"))

Related

Ruby - File.open(text_file.txt) is not able to find the file?

This is probably a simple "Navigating directory" problem since I'm new but..
Inside of a file named tasks_lists.rb I am attempting to save the text inside of a text file to a variable named draft.
Here is that code:
class FivePoints::Tasks
attr_accessor :draft, :efile, :serve
def self.start
binding.pry
draft = File.open("./text_files/draft.txt")
efile = File.open("./text_files/efile.txt")
serve = File.open("./text_files/serve.txt")
self.new(draft, efile, serve)
end
def initialize(draft , efile, serve)
#draft = draft
#efile = efile
#serve = serve
end
end
I have tried to pry around, but no luck. I have also tried variations such as ("../text_files/efile.txt"), ("/text_files/efile.txt"). I will attach an image of the directory tree as well.
I am simply trying to eventually puts out some text in the CLI for a sample program. That text will be in the draft.txt file. Any ideas?
Assuming you only want to run this locally, then find out the path of the file (you can view its properties from file explorer), and use that explicitly in your code.
Find the exact path (If you're on UNIX it'll be something like /home/USER/projects/five_points/bla....) then replace your string with the exact full path and you'll be able to open the files as needed
It looks like your files are in a directory called five_points but your code is under lib so one level higher ?
Also, you need to be sure you open the file for appending.
draft = File.open("./five_points/text_files/draft.txt", "a")

Importing a file into my app from a hosted account (godaddy)

I have already built several Rake tasks to import a series of CSV files into my PostgreSQL database, but I've always had those tasks directed to a path on my local computer.
I need to have the tasks set up to access a secure on directory so my client can simply copy files into this directory, and when the Rake task is executed it automatically pulls from the online source.
This seems like it would be a simple adjustment in my code but I'm not sure how to make it work. If anyone has any suggested reading or can quickly help edit my code it would be appreciated.
Below is a copy of one of my Rake tasks:
require 'csv'
namespace :import_command_vehicles_csv do
task :create_command_vehicles => :environment do
puts "Import Command Vehicles"
csv_text = File.read('/Users/Ben/Sites/ror/LFD/command_vehicles.csv', :encoding => 'windows-1251:utf-8')
csv = CSV.parse(csv_text, :headers => true)
csv.each_with_index do |row,index|
row = row.to_hash.with_indifferent_access
CommandVehicle.create!(row.to_hash.symbolize_keys)
command_vehicle = CommandVehicle.last
if #report_timesheet_hash.key?(command_vehicle.report_nr)
command_vehicle.timesheet_id = "#{#report_timesheet_hash[command_vehicle.report_nr]}"
end
#command_vehicle.timesheet_id = #timesheet_id_array[index]
command_vehicle.save
end
end
end
You can create rake tast that can accept parameters and then you can pass whatever path you like.
Check out this link Set Multiple Environmental Variables On Invocation of Rake Task to see how to pass parameters via enviroment variables and this link http://viget.com/extend/protip-passing-parameters-to-your-rake-tasks to see bracket notation.
'/Users/Ben/Sites/ror/LFD/command_vehicles.csv' will only work on your local machine, unless you have an identical path to your resources on the remote host, which is hardly likely. As a result, you need to change the absolute path, to one that is relative to your file.
I have a folder hierarchy on my Desktop, stuck several folders down, like:
- test
| lib
| - test.rb
| config
| - config.yaml
And test.rb contains:
File.realpath('../config/config.yaml', File.dirname(__FILE__))
__FILE__ is a special variable that returns the absolute path to the script currently being interpreted. That makes it easy to find where something else is if you know where it exists relative to the current __FILE__.
The value returned by realpath will be the absolute path to the "config.yaml" file, based on its relative path from the current file. In other words, that would return something like:
/Users/ttm/Desktop/tests/junk/test/config/config.yaml
The nice thing about Rake is it's really using Ruby scripts, so you can take advantage of things like File.realpath. Also, remember that Rake's idea of the current-working directory is based on the location of the script being run, so everything it wants to access has to be relative to the script's location, or an absolute path, or you have to change Rake's idea of the current-working directory by using a chdir or cd.
Doing the later makes my head hurt eventually so I prefer to define some constants pointing to the required resources, and figuring out the real absolute path becomes easy doing it this way.
See "How can I get the name of the command called for usage prompts in Ruby?"
for more information.

Rake: Processing files in a specified source directory

In my Rails project I have a specific list of externally-supplied files I want to process using Rake. My goal is to be able to specify the source directory of these files as an argument like so:
rake foofiles:process[vendor/sources]
Currently I'm specifying the file names (and their relative paths within the source directory) using a FileList assigned to a constant:
REQUIRED_FILES = FileList[
'blah.csv',
'subdir/something.csv',
'subdir/monkeys/foo.bar',
...
]
How can I prepend each of these files with my source directory argument so that I can make a task that depends on those files existing in that directory? (ideally nothing would happen without all those files being present)
For example, if I used the rake command as typed above, I'd need my task to depend on vendor/sources/blah.csv, vendor/sources/subdir/something.csv, vendor/sources/subdir/monkeys/foo.bar etc.
Edit: Adding a prefix to each element in an array/list is relatively trivial, I'm more confused about how to structure my task(s) and their dependencies so I can actually access the source folder argument I've supplied, then use the new prepended file list as a dependency for the processing task that actually does the work.
The main invoked task is gonna have to look something like this if I want the syntax I used at the top:
namespace :foofiles do
task :process, [:source_directory] => [???, my_newly_prepended_file_list] do |t, args|
# Do stuff
end
end
But I don't know how to provide the :source_directory argument to a task that does the prepending, and then subsequently return the prepended file list to the :process task as a dependency.
Why not just keep an array of the suffixes, then append the argument to the start of each element in the array, then create the filelist?
suffixes = [
'blah.csv',
'subdir/something.csv',
'subdir/monkeys/foo.bar',
]
files = suffixes.map { |suffix| File.join(prefix, suffix) }
file_list = FileList[*files]
Where prefix is the argument passed in.
I ended up just using an environment variable, it's much easier to work with in my case than Rake's built-in argument implementation. This way I can work with the variable and build my FileList with the prepended path (in the way Cameron suggested in the other answer) outside a task block:
namespace :foofiles do
REQUIRED_FILES = [...]
source_directory = ENV['SOURCEDIR'] || 'vendor/sources'
source_files = FileList[REQUIRED_FILES.map { |relative_path| File.join source_directory, relative_path }]
# Note: FileList can take an array inside the square brackets without needing the splat (*) operator
task process: source_files do
...
end
end
So now I can call it from the terminal like this:
SOURCEDIR=some/folder rake foofiles:process

How to access a yaml in rails config path

I'm writting a ruby gem and I want to let user use your own yaml file configuration, but I don't know how to test if the user_config.yml exists into rails config path.
I want to use user_config.yml only if this file exists into config path.
Rails.root (or RAILS_ROOT in earlier versions of Rails) gives you the path of the application root. From there, you can see if the file you're interested in exists.
e.g.
path = File.join(Rails.root, "config", "user_config.yml")
if File.exists?(path)
# do something
end
you can access your Rails App's load path with the $LOAD_PATH variable which is of type Array.
Thus
if $LOAD_PATH.include?('/path/where/user/should/put/their/user_config.yml')
# EDIT
config_options = File.new('rails_app/config/user_config.yml', 'r')
else
# EDIT
config_options = File.new('path/to/default/config.yml', 'r')
end
There is also another useful method for the Ruby File class called #exists? which will of course check to see if a file exists. See File class docs for more.
Hope this gets you started. Your question was rather vague, reply with more details if you need more help.

RoR - Where to put/initialize constant for a lib module

In my Rails 3 application, I have a module in the lib/ folder. The module requires a constant variable, which is a big dictionary loaded from a data file. Since the dictionary won't change over the course of the application and its time consuming to reload this data file everytime a method from the module is called, I want to create a constant which holds the dictionary that can be accessed by the module in the lib.
lib/my_module:
module My_Module
def do_something(x)
y = CONSTANTVAR[x]
...
end
end
to initialize the constant, I have to load a file:
file = File.new('dataFile.dat','r') #I'm not sure where to put this data file
file.each_line { |line|
lineInfo = line.split
CONSTANTVAR[line[0]] = line[1] }
file.close
Where is the standard place to initialize variables that can be accessed by modules in the lib folder (this is the only place I will be accessing the variable)?
Also, the module loads a data file, is it standard to put data files in the lib/ folder as well?
Thanks!
You can take a look on how it is done here: https://github.com/sevenwire/forgery
It is a lib for generating words and it uses dictionaries. They are saved in : /lib/forgery/dictionary/*
So, save you dictionary on /lib/module-name/dictionaries/DATA.dat
And you can initialise your variable in config/initialisers/module-name.rb
I should put my, say, init_dictionary.rb in config/initializers. I think it's the better place for your requirement.

Resources