Nathan W
Nathan W

Reputation: 516

How do I convert this Ruby String into an Array?

What is the best way to turn the following Ruby String into an Array (I'm using ruby 1.9.2/Rails 3.0.11)

Rails console:

>Item.first.ingredients
=> "[\"Bread, whole wheat, 100%, slice\", \"Egg Substitute\", \"new, Eggs, scrambled\"]"
>Item.first.ingredients.class.name
=> "String"
>Item.first.ingredients.length
77

The desired output:

>Item.first.ingredients_a
["Bread, whole wheat, 100%, slice", "Egg Substitute", "new, Eggs, scrambled"]
>Item.first.ingredients_a.class.name
=> "Array
>Item.first.ingredients_a.length
=> 3

If I do this, for instance:

>Array(Choice.first.ingredients)

I get this:

=> ["[\"Bread, whole wheat, 100%, slice\", \"Egg Substitute\", \"new, Eggs, scrambled\", \"Oats, rolled, old fashioned\", \"Syrup, pancake\", \"Water, tap\", \"Oil, olive blend\", \"Spice, cinnamon, ground\", \"Seeds, sunflower, kernels, dried\", \"Flavor, vanilla extract\", \"Honey, strained/extracted\", \"Raisins, seedless\", \"Cranberries, dried, swtnd\", \"Spice, ginger, ground\", \"Flour, whole wheat\"]"] 

I'm sure there must be some obvious way to solve this.

For clarity, this will be editable in a textarea field in a form, so should be made as secure as possible.

Upvotes: 5

Views: 4776

Answers (6)

Bryan Ash
Bryan Ash

Reputation: 4479

class Item
  def ingredients_a
    ingredients.gsub(/(\[\"|\"\])/, '').split('", "')
  end
end
  1. strip off the extraneous characters
  2. split into array elements using the separating pattern

Upvotes: 5

Liber
Liber

Reputation: 840

If your string-array is standard JSON format, just use JSON.parse()

Upvotes: 0

Andrew Marshall
Andrew Marshall

Reputation: 96914

What you have looks like JSON, so you can do:

JSON.parse "[\"Bread, whole wheat, 100%, slice\", \"Egg Substitute\", \"new, Eggs, scrambled\"]"
#=> ["Bread, whole wheat, 100%, slice", "Egg Substitute", "new, Eggs, scrambled"]

this avoids a lot of the horrors of using eval.

Though you should really think about why you're storing your data like that in the first place, and consider changing it so you don't have to do this. Further, it's likely that you should be parsing it to an array in ingredients so that the method returns something more meaningful. If you're almost always doing the same operation on a method's return value, the method is wrong.

Upvotes: 9

Michael Stalker
Michael Stalker

Reputation: 1367

Like Mark Thomas said, modify your ingredients method, unless you really want two separate methods that return a string and an array, respectively. I'll assume you really only want to return an array. For the sake of argument, let's say your ingredients method currently returns a variable named ingredients_string. Modify your method like so:

def ingredients
  ...
  ingredients_array = ingredients_string.split('"')
  ingredients_array.delete_if { |element| %(", "[", "]").include? element }
  ingredients_array
end

Upvotes: 1

CambridgeMike
CambridgeMike

Reputation: 4622

Not sure if this comes into play, but what happens if you want to use an array as an attribute, you might want to consider serialize..

class Item << ActiveWhatever
  serialize :ingredients, Array

  ...
end

More info on serialize here http://api.rubyonrails.org/classes/ActiveRecord/Base.html

Upvotes: 0

Mark Thomas
Mark Thomas

Reputation: 37507

It looks like the ingredients method returns the .inspect output of the resulting return array. It is not very useful output that way. Do you have the ability to change it to return a plain array?

What I would not do is use eval, which will just increase the hackiness of already hacky code.

Upvotes: 1

Related Questions