রেল কি জাদু তৈরি বা আপডেট করে?


95

আমার একটি ক্লাস আছে CachedObjectযা জেনেরিক সিরিয়ালাইজড অবজেক্টগুলিকে কী অনুসারে সঞ্চয় করে। আমি চাই এই ক্লাসটি কোনও create_or_updateপদ্ধতি বাস্তবায়ন করুক। যদি কোনও বস্তু পাওয়া যায় তবে এটি আপডেট করবে, অন্যথায় এটি একটি নতুন তৈরি করবে।

রেলগুলিতে এটি করার কোনও উপায় আছে বা আমার নিজের পদ্ধতিটি লিখতে হবে?

উত্তর:


175

রেল 6

6 রেলগুলি একটি upsertএবং upsert_allপদ্ধতিগুলি যুক্ত করেছে যা এই কার্যকারিতা সরবরাহ করে।

Model.upsert(column_name: value)

[উত্থাপন] এটি কোনও মডেলকে তাত্পর্যপূর্ণ করে না এবং এটি সক্রিয় রেকর্ড কলব্যাকস বা বৈধতাগুলিকে ট্রিগার করে না।

5, 4, এবং 3 এর কড়া

আপনি যদি কোনও "উপস্থাপক" (যেখানে একই ডাটাবেসটিতে কোনও আপডেট বা একটি সন্নিবেশ বিবৃতি কার্যকর করে) ধরণের বিবৃতি সন্ধান করছেন Not বাক্সের বাইরে, রেলস এবং অ্যাক্টিভেকর্ডের এমন কোনও বৈশিষ্ট্য নেই। তবে আপনি উপগ্রহ রত্নটি ব্যবহার করতে পারেন ।

অন্যথায়, আপনি ব্যবহার করতে পারেন: find_or_initialize_byবা find_or_create_by, যা অতিরিক্ত ডাটাবেস হিট ব্যয় করে অনুরূপ কার্যকারিতা সরবরাহ করে, যা বেশিরভাগ ক্ষেত্রেই খুব কমই সমস্যা হয়। সুতরাং আপনার যদি পারফরম্যান্সের গুরুতর সমস্যা না থাকে তবে আমি রত্নটি ব্যবহার করব না।

উদাহরণস্বরূপ, যদি কোনও ব্যবহারকারী "রজার" নামের সাথে খুঁজে পাওয়া যায় না, তবে একটি নতুন ব্যবহারকারীর উদাহরণটি name"রজার" এ সেট করে ইনস্ট্যান্ট করা হয় ।

user = User.where(name: "Roger").first_or_initialize
user.email = "email@example.com"
user.save

বিকল্পভাবে, আপনি ব্যবহার করতে পারেন find_or_initialize_by

user = User.find_or_initialize_by(name: "Roger")

কারাগারে 3।

user = User.find_or_initialize_by_name("Roger")
user.email = "email@example.com"
user.save

আপনি একটি ব্লক ব্যবহার করতে পারেন, তবে রেকর্ডটি নতুন হলে কেবল ব্লকটি চলে

User.where(name: "Roger").first_or_initialize do |user|
  # this won't run if a user with name "Roger" is found
  user.save 
end

User.find_or_initialize_by(name: "Roger") do |user|
  # this also won't run if a user with name "Roger" is found
  user.save
end

আপনি যদি রেকর্ডের অধ্যবসায়ের কথা বিবেচনা না করেই কোনও ব্লক ব্যবহার করতে চান তবে ফলাফলটিতে ব্যবহার tapকরুন:

User.where(name: "Roger").first_or_initialize.tap do |user|
  user.email = "email@example.com"
  user.save
end


4
দস্তাবেজটি সূত্রের নির্দেশ দেয় যে উত্স কোডটি এটি দেখায় যে এটি আপনার কাজ করে এমনভাবে কাজ করে না - ব্লকটি কোনও নতুন পদ্ধতিতে কেবল তখনই প্রেরণ করা হয় যদি সম্পর্কিত রেকর্ডের অস্তিত্ব না থাকে। রেলগুলিতে কোনও "আপসেট" যাদু নেই বলে মনে হচ্ছে - আপনাকে এটিকে দুটি রুবি স্টেটমেন্টে আলাদা করতে হবে, একটি অবজেক্ট নির্বাচনের জন্য এবং একটি বৈশিষ্ট্য আপডেটের জন্য।
সমরাহ

@ সমীরগণ আমি নিশ্চিত না যে আপনি কী বলতে চাইছেন তা আমি বুঝতে পেরেছি। আপনি কী ভাবছেন আমি বোঝাচ্ছি?
মোহাম্মাদ

4
ওহ ... আমি এখন আপনি কী বোঝাতে চেয়েছেন তা - এটি উভয়ই ফর্ম, find_or_initialize_byএবং find_or_create_byএকটি ব্লক গ্রহণ করে। আমি ভেবেছিলাম আপনি বোঝাতে চেয়েছিলেন যে রেকর্ডটি বিদ্যমান কিনা বা না থাকুক, আপডেটটি করার জন্য একটি ব্লকটি আর্গুমেন্ট হিসাবে রেকর্ড অবজেক্টের সাথে পাস করা হবে।
ব্যক্তি

4
এটি সামান্য বিভ্রান্তিকর, জরুরী উত্তর নয়, তবে এপিআই। যে কেউ নির্বিশেষে ব্লকটি পাস হওয়ার আশা করবে এবং সুতরাং সেই অনুযায়ী তৈরি / আপডেট করা যেতে পারে। পরিবর্তে, আমাদের এটি আলাদা বিবৃতিতে ছড়িয়ে দিতে হবে। বু। <3 রেল যদিও :)
ভল্ট

32

4 রেলগুলিতে আপনি একটি নির্দিষ্ট মডেল যুক্ত করতে পারেন:

def self.update_or_create(attributes)
  assign_or_new(attributes).save
end

def self.assign_or_new(attributes)
  obj = first || new
  obj.assign_attributes(attributes)
  obj
end

এবং এটি পছন্দ করুন

User.where(email: "a@b.com").update_or_create(name: "Mr A Bbb")

অথবা আপনি যদি প্রাথমিক পদ্ধতিতে লাগানো সমস্ত মডেলগুলিতে এই পদ্ধতিগুলি যুক্ত করতে পছন্দ করেন:

module ActiveRecordExtras
  module Relation
    extend ActiveSupport::Concern

    module ClassMethods
      def update_or_create(attributes)
        assign_or_new(attributes).save
      end

      def update_or_create!(attributes)
        assign_or_new(attributes).save!
      end

      def assign_or_new(attributes)
        obj = first || new
        obj.assign_attributes(attributes)
        obj
      end
    end
  end
end

ActiveRecord::Base.send :include, ActiveRecordExtras::Relation

4
assign_or_newটেবিলের প্রথম সারিটি উপস্থিত থাকলে কী ফিরে পাবেন না এবং তারপরে সেই সারিটি আপডেট হবে? এটা আমার জন্য মনে হচ্ছে।
স্টিভ ক্লিন

User.where(email: "a@b.com").firstযদি পাওয়া না যায় তবে শিরোনাম ফিরে আসবে। আপনার whereসুযোগ রয়েছে তা নিশ্চিত করুন
মন্ট্রিআলমিক 19

কেবলমাত্র একটি নোট যা updated_atস্পর্শ করা হবে না কারণ assign_attributesএটি ব্যবহার করা হয়েছে
lshepstone

এটা আপনি assing_or_new না ব্যবহার করছেন হয় হবে কিন্তু আপনি সংরক্ষণ কারণে update_or_create ব্যবহার করবে যদি
montrealmike

13

এটি আপনার মডেলটিতে যুক্ত করুন:

def self.update_or_create_by(args, attributes)
  obj = self.find_or_create_by(args)
  obj.update(attributes)
  return obj
end

এটির সাহায্যে আপনি:

User.update_or_create_by({name: 'Joe'}, attributes)

দ্বিতীয় অংশ আমি কাজ করব না। ক্লাস স্তর থেকে একক রেকর্ড আপডেট করতে পারে না রেকর্ডের আইডি ছাড়া আপডেট করতে।
আয়ারামোর

4
আপত্তি = স্ব.ফাইন্ড_ও_ক্রিয়েট_বি (আরগস); obj.update (গুণাবলী); রিটার্ন আপত্তি; কাজ করবে
বীরাশ ইয়াহ

12

যাদু আপনার জন্য যোগ করা হয়েছে খুঁজছেন হয়েছে Rails 6 এখন আপনি করতে পারেন upsert (আপডেট অথবা সন্নিবেশ)। একক রেকর্ড ব্যবহারের জন্য:

Model.upsert(column_name: value)

একাধিক রেকর্ডের জন্য upsert_all ব্যবহার করুন :

Model.upsert_all(column_name: value, unique_by: :column_name)

দ্রষ্টব্য :

  • উভয় পদ্ধতিই সক্রিয় রেকর্ড কলব্যাকস বা বৈধতাগুলিকে ট্রিগার করে না
  • অনন্য_বাই => পোস্টগ্র্যাস এসকিউএল এবং এসকিউএলাইট কেবল

1

পুরানো প্রশ্ন কিন্তু সম্পূর্ণতার জন্য আমার সমাধানটি রিংয়ের মধ্যে ফেলে দিচ্ছে। যখন আমার একটি সুনির্দিষ্ট সন্ধানের প্রয়োজন ছিল তবে এটির অস্তিত্ব না থাকলে একটি আলাদা তৈরির দরকার ছিল I

def self.find_by_or_create_with(args, attributes) # READ CAREFULLY! args for finding, attributes for creating!
        obj = self.find_or_initialize_by(args)
        return obj if obj.persisted?
        return obj if obj.update_attributes(attributes) 
end

0

আপনি এটি একটি বিবৃতিতে এটি করতে পারেন:

CachedObject.where(key: "the given key").first_or_create! do |cached|
   cached.attribute1 = 'attribute value'
   cached.attribute2 = 'attribute value'
end

9
এটি কাজ করবে না, যেহেতু এটি পাওয়া যায় কেবলমাত্র এটি মূল রেকর্ডটি ফিরিয়ে দেবে। ওপি এমন একটি সমাধান চেয়েছে যা সর্বদা মান পরিবর্তন করে, এমনকি কোনও রেকর্ড পাওয়া গেলেও found
জিনমার্টজ

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.