简体   繁体   中英

How to map using constants in Ruby

I'm trying to map an array of custom values using a constant that's already defined. I'm running into some problems.

This works perfectly:

Car.where(brand: car_brands.map(&:Car_honda))

Although I have all the car brands already defined in my file, so I would prefer to use the constants over rewriting the names. For example:

HONDA = "Car_honda"

When I try and map this constant to the array it doesn't seem to work properly:

Car.where(brand: car_brands.map(&:HONDA))

I tried to use a block with map , but I still got the same result:

Car.where(brand: car_brands.map {|c| c.HONDA}))

Are we able to use constants with map ?

只需使用send

Car.where(brand: car_brands.map { |c| c.send(HONDA) })

I'm not sure where you're going with this, or precisely where you're coming from, but here's an example that follows Rails conventions:

class Brand < ActiveRecord::Base
  has_many :cars
end

class Car < ActiveRecord::Base
  belongs_to :brand
end

Then you can find all cars associated with the "Honda" brand:

Brand.find_by(name: 'Honda').cars

Or find all cars matching one or more arbitrary brand names using a JOIN operation:

Car.joins(:brand).where(brand: { name: %w[ Honda Ford ] })

If you go with the flow in Rails things are a lot easier.

Are you able to use constants with map?

Nope. Not like this, anyhow.

car_brands.map { |c| c.HONDA }

This means, for every thing in car_brands call method HONDA on it and return results of the invocations. So, unless you have method HONDA defined (which you absolutely shouldn't), this has no chance to work.

Constants are defined on the class, not on the object. You can invoke them through .class .

:005 > Integer.const_set('ABC', 1)
 => 1
:006 > Integer::ABC
 => 1
:007 > [1,2,3].map {|i| i.class::ABC}
 => [1, 1, 1]

This will not work for your use case unless car_brands contains an array of different Car classes.

First off, you probably don't want to things this way. Perhaps it's the way your example is worded, but the only way it makes sense, as I'm reading it, is if Car_brands is an array of classes. And if that's the case, if doesn't make sense to have a constant called HONDA . If anything, you would have a constant called BRAND that might equal "Honda" for a given class. I strongly recommend you rethink your data structures before moving forward.

All that said, you can use const_get to access constants using map. eg

class CarBrand1
  BRAND = 'Honda'
end

class CarBrand2
  BRAND = 'Toyota'
end

car_brands = [CarBrand1, CarBrand2]

car_brands.map{|car_brand| car_brand.const_get("BRAND")}
car_brands.map{|car_brand| car_brand::BRAND} # Alternatively
# => ["Honda", "Toyota"]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM