Em 15-10-2013 17:49, Jeremy Evans escreveu:


On Tuesday, October 15, 2013 12:47:30 PM UTC-7, Rodrigo Rosenfeld Rosas wrote:

    Em 15-10-2013 16:38, Jeremy Evans escreveu:
    On Tuesday, October 15, 2013 10:07:53 AM UTC-7, Rodrigo Rosenfeld
    Rosas wrote:

        Is there any alternative in Sequel for ActiveRecord's
        find_or_initialize_by class method?

        
http://edgeapi.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_initialize_by
        
<http://edgeapi.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_initialize_by>
        
http://guides.rubyonrails.org/active_record_querying.html#find-or-initialize-by
        
<http://guides.rubyonrails.org/active_record_querying.html#find-or-initialize-by>

        I could only find find_or_create:

        
http://sequel.rubyforge.org/rdoc/classes/Sequel/Model/ClassMethods.html#method-i-find_or_create
        
<http://sequel.rubyforge.org/rdoc/classes/Sequel/Model/ClassMethods.html#method-i-find_or_create>

        Thanks in advance,
        Rodrigo.


    Nope, there isn't an alternative method.  You can do:

      object = Model.find(...) || Model.new(...)

    Yes, I'm using the exact same implementation as AR in a custom plugin:

    module ClassMethods
      def find_or_initialize(attributes, &block)
        find(attributes) || new(attributes, &block)
      end
    end

    I'm not sure this method is common enough to be warrant adding to
    Sequel::Model itself.  As it is trivial to implement yourself,
    there doesn't seem to be a good reason to add it.

    I believe it's quite common. This is the second time I felt the
    need for it in my application.

    This is very common in some save actions where you either update
    or create a record but where find_or_create is not suitable.

    Also, implementation of find_or_create is also trivial, but it's
    part of the core.

    Here's a typical usage:

    comment = FieldValueComment.find_or_initialize(transaction_id:
    params[:transaction_id].to_i, field_id: params[:field_id].to_i)
    # you can't use find_or_create because date and message are
    required columns
    comment.date = Time.now
    comment.message = params[:message].strip
    comment.save raise_on_failure: true
    render :ok

    It seems find_or_initialize_by is used a lot in open-source code
    in GitHub:

    https://github.com/search?q=find_or_initialize_by&ref=cmdform&type=Code
    <https://github.com/search?q=find_or_initialize_by&ref=cmdform&type=Code>

    " We've found 2,807 code results"

    Hopefully this could be part of core Sequel.


find_or_create is significantly more popular:

https://github.com/search?q=find_or_create&ref=cmdform&type=Code


       "We've found 8,397 code results"


Yes, there are a few places where find_or_initialize_by will work where find_or_create will not, namely, where there are attributes that must be present to save that are not in the provided hash. However, there are probably a large number of helper methods than can be added that are of similar usefulness. One of Sequel's design philosophies is to keep a small core. If I added all of the potentially useful helper methods to core, Sequel would end up bloated, and I don't want that. I don't think the benefits are worth the costs in this case.

Now, I could be wrong about this. Maybe, in spite of the fact that nobody has previously asked about this method in the 5+ years I have been maintaining Sequel, it is wildly popular in the Sequel community, and everyone just adds it locally, but never thought to ask me to include it. If that is the case, please speak up.

FWIW, instead a find_or_initalize_by, I think a better API would be something like:

  def update_or_create(attrs, update_attrs=nil)
    obj = find(attrs) || new(attrs)
    obj.set(update_attrs) if update_attrs
    yield obj if block_given?
    obj.save_changes
  end

FieldValueComment.update_or_create(transaction_id: params[:transaction_id].to_i, field_id: params[:field_id].to_i) do |comment|
    comment.date = Time.now
    comment.message = params[:message].strip
  end
  # or
FieldValueComment.update_or_create({transaction_id: params[:transaction_id].to_i, field_id: params[:field_id].to_i}, {date: Time.now, message: params[:message].strip})

An object retrieved via find_or_initialize_by is virtually always going to end with saving the object, so it's better to have a method that is designed specifically for that use case.

Yes, I agree and I've considered doing this myself too. But I thought it might be easier to convince you to add a find_or_initialize first ;)

I agree that most of the time one would be doing this update_or_create thing and such API would be very welcomed by me if you are ok with adding it to core.

Thanks,
Rodrigo.

--
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to