اعتبار سنجی ورودی در Phoenix


#1

سلام
فرض کنید از یک فرم داده هایی به نام name , age به تابع زیر ارسال میشن :

def make(conn,%{“age” => age,“name” => name} = params) do

end

هردوی این متغیر ها لازمه که اعتبار سنجی بشن تا کاربر مقدار null نفرسته ، فضالی خالی نفرسته ، برای age فقط سن بفرسته، ممکنه یادش بره age رو نفرسته در نتیجه دیگه چیزی به اسم age در map وجود نداشته باشه و … ، در ضمن از Ecto.Changeset هم قرار نیست استفاده ای بشه !
1-باید از صحت وجود هردو مطمئن بشم !
2- باید هیچکدوم از متغیر ها “” یا nil نباشن
3- باید از اینکه age یک عدد صحیح تا 100 هست مطمئن بشم
4 - اگر کاربر یادش رفت هر کدوم رو بفرسته در نتیجه داخل map دیگه وجود نخواهد داشت ، مثلا اگر یادش رفت age رو بفرسته ساختار map این میشه :
%{“name” => “mortza”}
و میخوام که تمام این موارد رو بتونم کنترل کنم .
شما همچین چیزی رو چجوری کدنویسی میکنید لطفا راهنمایی کنید تشکر


#2

درود .

وقتی شما توی تابع اکشن دارید مشخص می کنید طرف چه پارامتر هایی بفرسته مطمئن هستید که اگر پارامتر ارسال نشه پس ارور می ده . اینجا نیازی نیست چیزی دیگه ای بنویسید .

چرا نمی خواین ازش استفاده کنید ؟

اگر از Ecto.Changeset بخواین استفاده کنید دیگه نیازی نیست خیلی کد برای ولیدیشن بنویسید .

به صورت مثال چون تیبل مورد نظر از نوع عدد اینتیجر هست و شما هم مشخص کردید که اینطور باشه پس وقتی عدد بدی توش می ره ارور بر می گرده به ecto و بعد شما متوجه می شید که مشکل داره بدون اینکه بخواهید کد دیگه ای بنویسید و همینطور اونجا می تونید مشخص کنید این عدد از چند تا چند باشه با یک خط ساده

چون مشخص می کنید null نباشه در زمانی که می خواهید دیتابیس رو معرفی کنید پس بازم امکان null فرستادن نداره

می تونید از فانکشن اکشن چند نوع بسازید

def make(conn,%{“age” => age,“name” => name} = params) do

def make(conn,%{“name” => name} = params) do

def make(conn,%{“age” => age} = params) do

می تونید یک تعداد حرورف مشخص بکنید . می تونید اینجا یک رجکس بزارید که فقط از حروف مثلا انگلیسی استفاده بشه مثلا می تونید اینجا بگید از اسپیس استفاده نشه که بازم تو چنج ست می تونید یک تابع کاستوم بسازید

توی فونیکس شما نمی یای ولیدیشن بنویسی چون ارور بر می گرده از دیتابیس به ecto و شما هم به راحتی بهش دسترسی پیدا می کنید

یک تابع کاستوم برای چنجست

 defp check_password(changeset, field, options \\ []) do
        validate_change(changeset, field, fn field, pass ->
            case Security.validate_password_strength(pass) do
              true -> []
              false -> [{field, options[:message] || "the password is too weak"}]
            end
        end)
    end

اصلا از فونیکس الکسیر استفاده می کنیم که به اکتو دسترسی داشته باشیم :sweat_smile: اگر نه که باید خیلی ولیدیشن و … نوشته بشه که من اصلا به اون فکر نمی کنم می رفتم توی php کد می زدم

راستی می تونی کتاب خونه اکتو رو ببینی و ازش کد کپی پست کنی اگر نمی خوای کامل پیاده کنی


#3

بحث سر اینه که میخوام تمام این خطاها رو خودم کنترل کنم .

چون نیازی بهش ندارم و فکر نکنم عاقلانه باشه بخاطر یه اعتبار سنجی ازش استفاده کنم

میخوام خودم کنترلش کنم ، وقتی تعداد درخواست بالا رفت نمیشه که هربار درخواست بفرسته دیتابیس اگر null شد برگردونه !

اینطوری هم باید بالای 7 تا اکشن داشته باشم که تو هرکدوم با nil و “” بازی کنم و امتحان کردم جالب نبود.

مساله اینه که میخوام تمامش رو خودم کنترل کنم و بیخوی به دیتا بیس درخواست فرستاده نشه و ecto در پروژه وجود نداره

آخ اخ گفتی بخدا یکی از دلایلی که از php فرار کردم همین قضیه بود دیگه حالم از isset و … بهم میخورد

این رو حتما امتحان میکنم ممنون

راستی خودم همچین چیزی رو نوشتم اما اینم دوست ندارم و چنگی به دل نمیزنه باید راه بهتر و جالبتری باشه
params = %{“name” => “”,“age” => 200}

case Map.take(params,["age","name"]) do
	%{"name" => nil,"age" => nil} -> :both_nil
	%{"name" => "","age" => ""} -> :both_empty
	%{"name" => nil} -> :name_nil
	%{"age" => nil} -> :age_nil
	%{"name" => ""} -> :name_empty
	%{"age" => "" } -> :age_empty
	%{"age" => age,"name" => name} when age in 12..100 and name != "" -> IO.puts "okay"
	_ -> IO.puts "err"
end

اما اینم چنگی به دل نمیزنه مطمئن هستم که راه بهتری هست فقط نمیتونم پیدا کنم ، اگر Ecto بود میشد با
field name,:string,virtual: true
و … نوشتن یک changeset ساده براحتی تمام این ها رو حل کرد اما مساله اینه که ecto لازم نیست و عاقلانه هم نیست بخاطر اعتبار سنجی ازش استفاده بکنم ! بازم راه بهتری داری خوشحال میشم راهنمایی کنید


#4

اینی که خودم نوشتم هم اصلا چنگی به دل نمیزنه و نمیشه بعضی از خطاها یا چیزهایی که لازمه رو چک کرد و به کاربر پیغام مناسب رو فرستاد ، یواش یواش میخوام سرمو بکوبم به دیوار


#5

پست @shahryarjb خیلی کامل بود و‌در مورد Ecto و Phoenix کاملا درست میگه :+1::+1::+1:
من پیشنهاد میکنم کلا برگردی به قبل از اختراع چرخ و همه چیز رو از اول درست کنی :grin::grin::grin:


#6

توماج عزیز لطف دارند . من همه اینارو در پست هایی که از ایشون و @samdvr عزیز پرسیدم برداشت کردم .

منم اول دنبال همین راهکار بودم که بعدا پشیمون شدم من الان اگر Ecto رو حتی برای دیتابیس نیاز نداشته باشم بازم نصب می کنم دلیل اینجاست که واقعا توابع و مواردی که داره مخصوصا جامعه خوبی که پشتش هست برای به روز رسانی کلیدی هست که دیگه آدم کد های پر اشتباه و پر باگ نزنه مثلا الان رجکس بزنی انگار داری خودتو آتیش می زنی

معرفی رجکس در یک پست کوتاه

بعد می خواین تک به تک دنبال فانکشن های الکسیر باشید دوباره بنویسید ؟ خوب آماده هست خیلی فکر پشتش بوده چرا نباید از اون استفاده کنید؟

می تونی از with هم استفاده کنی. می تونی از گارد استفاده کنی . می تونی از چند فانکشن استفاده کنی می تونی از همینی که گفتید هم استفاده کنید شکلش خیلی خوبه تمیزم هست قابل فهمه

وقتی اکتو ارور می ده بهت می گه ولید هست یا نه اونجا بر اساس شرطی که می زاری می تونی بگی اگر ولید بود این نبود اون که اینم باز در الکسیر و فونیکس می گند نکنید وقتی خودش انجام می ده ولی شما اسرار داری . خیلی کنترل زیادی اکتو بهت می ده فکر کنم چون استفاده کامل نکردید بد بین هستید بهش و اگر کردید هنوز کامل جا نیفتاده برات.

اگر به دیتابیس وصل می شید ECTO ضروری هست به نظرم بنده بهتون یک نمونه فایل دادم که اگر این رو در php می خواستم بنویسم که نوشتم قبلا الان سه تا فایل کامل کد بود

اصلا باید به دیتابیس ارسال بشه که ارور برگرده

نیاز نیست همشو درست کنی ببن می تونی خلاقیت خرج بدی می تونی کمترین حالت رو در بیاری مثلا توی همه id باید باشه و name ولی بقیه نه اینجوری کاربر فورس می شه که name,id رو بفرسته ولی اگر بیشتر فرستاد تو مپ می یاد ولی کمتر نمی تونه

خیلی هاشو چنج ست جلوشو می گیره که به دیتابیس نره
فانکشن اکشن جلوشو می گیره
پلاگ جلوشو می گیره

راه خیلی هست


#7

قرار در نسخه ۳ اکتو validation کامل جدا بشه


الان کتاب خانه های validation موجوده اما هیچ کدام به خوبی اکتو نیست


#8

لطفا برای چند دقیقه خودت رو بزار جای من و فکر کن نباید از اکتو استفاده کنی بعد کدش رو لطف کن بنویس ، واقعا دوست دارم ببینم چجوری انجام میدی تا منم یاد بگیرم ، من به اندازه شما تو fp مهارت ندارم و دوست دارم اون مهارت لازم رو بدست بیارم ، همیشه نباید که از با زاویه اختراع چرخ دوباره نگاه کرد گاهی اوقات آدم دوست داره خودش به مهارت و توانایی لازم برسه. باور کنید در مورد استفاده از اکتو و مزیت هاش منم میدونم و اگر قرار بود از اکتو استفاده کنم سوالم رو مطرح نمیکردم


#9

شهریار جان ممنون بابت راهنمایی مفصل و کاملت و وقتی که گذاشتی ، عزیز من همون اول نوشتم که نمیخوام از اکتو استفاده کنم وگرنه لازم نبود این پست رو مطرح کنم ، من بیشتر دوست داشتم @toomaj عزیز تجربه چندین ساله خودش رو در این مورد در اختیار ما قرار بده و کدی بنویسه که من دید کافی رو نسبت به این موارد داشته باشم و اگر قرار بود از کتاب خونه استفاده کنم میتونستم بجای ecto هم با کمی جستجو یه کتابخونه دیگه برای اعتبار سنجی پیدا کنم اما بحث سر تخلیه اطلاعاتی هست که ظاهرا عزیزان علاقه ای ندارند چیزی یاد بدند و اطلاعاتی رو در اختیار قرار میدن که با کمی جستجو در گوگل میشه براحتی پیدا کرد


#10

ممنون عزیز از پاسختون اما سوال من این بود :

لطفا راهنمایی کنید ، اگر کد نویسی برای هردو پارامتر از حوصله شما خارجه لطفا فقط برای یک پارامتر مثلاً age کد مثال بنویسید تا بتونیم از تجربیات شما استفاده کنیم ، مواردی که شما اشاره کردین در گوگل میشه پیدا کرد و احتیاجی به سوال کردن نداره تا وقت شما عزیزان رو بگیرم ، من میخوام از تجربیات و مهارت شما استفاده کنم و ببینم که شما چجوری مینویسید تا با کدهای خودم مقایسه کنم و بدونم کجاها ایراد دارم وگرنه https://hex.pm/ اینجا حتما میشه دوسه تا کتابخونه اعتبار سنجی خوب پیدا کرد و احتیاجی به سوال نیست


#11

الان کلوژور یاد گرفته بودم @lxsameer ایکی ثانیه منو راهنمایی کرده بود و بهترین مثال ها رو در اختیارم قرار داده بود :grimacing::grimacing::grimacing::grimacing::joy::joy::joy:


#12

بلاخره کلوژر خدمات پس از فروش بهتری داره :joy::joy::joy:


#13
defmodule ValidationExample do
  def validate(%{name: "", age: _}) do
    show_error()
  end

  def validate(%{name: _, age: ""}) do
    show_error()
  end

  def validate(%{name: _}) do
    show_error()
  end

  def validate(%{age: _}) do
    show_error()
  end

  def validate(%{name: name, age: age}) do
    if name != "" && age != "" do
      IO.puts(name)
      IO.puts(age)
    end
  end

  def show_error do
    "some error"
  end
end


#14


اون فانکشن اولی همیشه مچ میشه نمیزاره نوبت بقیه برسه :cold_sweat::cold_sweat::scream:


#15

بله اول درست نوشته بودم حالت صحیح باید در آخر باشه تا مچ بشه به روز شد


#16

@mortezaKcode یک bug دیگه هم حل کردم


#17


در مورد اول که کلا با خطا مچ میشه

در مورد دوم که اصولا باید مچ بشه ولی نمیشه


#18

defmodule ValidationExample do
  def validate(%{name: "", age: _}) do
    show_error()
  end

  def validate(%{name: _, age: ""}) do
    show_error()
  end

  def validate(%{name: name, age: age}) do
    IO.puts(name)
    IO.puts(age)
  end

  def validate(%{name: _}) do
    show_error()
  end

  def validate(%{age: _}) do
    show_error()
  end

  def show_error do
    "some error"
  end
end


باید function هارو جابجا میکردم تا درست مچ بشه


#19

ممنون بابت وقتی که گذاشتین ، بنظر شما راه بهتر همینه یا داخل یک تابع با case ,cond و … هم انجام بدیم فرقی نداره ؟ یا بهتر همینه همینجوری انجام بدیم؟


#20

میل خودته من چند ساله به الیکسیر دست نزدم راه های بهتر نمیدونم کد طوری بنویس که خودت راحت تره برات