2 ms·
Slightly less worse, but the original function that I inputted into ChatGPT to generate the code from my message was this: def create_user(email)
by whstl 3y ago
Slightly less worse, but the original function that I inputted into ChatGPT to generate the code from my message was this:
def create_user(email)
user = User.create(email: email)
user.roles << Roles.find_by(name: 'admin')
user.permissions << Permissions.find_by(name: 'invite')
Templates.find_by(name: 'invite').call(user: user)
end
IMO this 4 line function is significantly better in terms of clarity, readability, and it avoids unnecessary state. Testability and encapsulation are the same.
(I would argue that the encapsulation is better with a function, since encapsulation is way too easy to break in Ruby, but hey, that's me)
- vidarh 3y agoI think the choice between a method (ruby doesn't have functions ;) ) and a class here may well be right. The only reason for using a class here is more as a general principle if you want it to be easier to pass your "usercreator" around as a value, but you can of course wrap it in a lambda if needed or use `#method`. Alternatively you can just make it a lambda from the start. If your main objection to the class is the ease of breaking encapsulation, lambda's are quite nice for tighter encapsulation of state in Ruby. E.g. lambda do state = 0 ->() { state += 1 } end.call (Note the `.call` at the end - we don't want the outer lambda; that is just used for creating the variables that will hold the state - we want the inner lambda) So let's say that for some stupid reason your user creator object needs to keep a count of users, you could "seal" that state into a lambda with the above technique, and make it really hard (I'm not sure if impossible) to break encapsulation. E.g. instance_eval or trying obtain the binding doesn't work, because they both will get you the state of the Proc object containing the closure, not the local variables accessible within it.