I am trying to think of a more elegant way to pass elements of an array as individual arguments to a method.
So far, I have the following code:
def fetch_data(keywords)
Product.where("name ILIKE ? AND type ILIKE ?", *construct_keywords(keywords))
end
def construct_keywords(keywords)
keywords.map{ |keyword| "%#{keyword}%" }
end
This works just fine, and I know that the splat operator is doing a good job but I want to see if instead of using that ugly asterisk, it is possible to reshape the return value of construct_keywords
in a way so that the fetch_data method will recognize the array elements as individual arguments. So ultimately I want it to be like:
def fetch_data(keywords)
Product.where("name ILIKE ? AND type ILIKE ?", construct_keywords(keywords))
end
def construct_keywords(keywords)
keywords.map{ |keyword| "%#{keyword}%" }
# reshape above array in a way so that fetch_data will recognize each elements as arguments
end
Thank you in advance.
Although that might be convenient, there's no way to directly inform how your return value will be used and have it "pre-splatted". That's something the method being called has to implement.
You might want to explore using keyword-based placeholders, like name ILIKE :name
where you can then create a hash that matches.
Right now you pass in an arbitrary number of keywords
to a method that returns an arbitrary-sized result array, which then binds to a query with precisely two places. That seems like it's prone to failure.
Using [ :name, :type ].zip(keywords.map { ... }).to_h
gives you something that can slot into that, of course, presuming you have two keyword args.
Although it might take some refactoring, a form that's really hard to foul up looks like this:
def fetch_data(name:, type:)
Product.where("name ILIKE :name AND type ILIKE :type", name: name, type: type)
end
Where those keyword arguments must be specified, and there can only be two.