{"id":34254,"date":"2025-11-14T00:31:29","date_gmt":"2025-11-13T21:31:29","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/"},"modified":"2025-11-14T00:31:29","modified_gmt":"2025-11-13T21:31:29","slug":"inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/","title":{"rendered":"Inline D\u00fczenleme: Rails&#8217;te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi"},"content":{"rendered":"<p><body><\/p>\n<p>Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan kald\u0131rarak ak\u0131c\u0131 bir etkile\u015fim sunmak, kullan\u0131c\u0131lar\u0131n uygulaman\u0131zda daha fazla zaman ge\u00e7irmesini sa\u011fl\u0131yor. Peki, Rails gibi geleneksel sunucu tarafl\u0131 render motoruyla bu SPA (Single Page Application) benzeri deneyimi nas\u0131l yakalayabiliriz? \u0130\u015fte tam da bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails uygulamalar\u0131n\u0131za sat\u0131r i\u00e7i d\u00fczenleme (inline editing) g\u00fcc\u00fc kat\u0131yor. Bu makale, Rails backend&#8217;ini modern frontend yetenekleriyle birle\u015ftirerek kullan\u0131c\u0131lar\u0131n\u0131za kesintisiz bir deneyim sunman\u0131z i\u00e7in size ad\u0131m ad\u0131m rehberlik edecek.<\/p>\n<p>G\u00fcn\u00fcm\u00fcz dijital d\u00fcnyas\u0131nda kullan\u0131c\u0131lar, uygulamalardan y\u00fcksek h\u0131z, kesintisizlik ve sezgisellik beklemektedir. Eskiden bir veriyi d\u00fczenlemek i\u00e7in ayr\u0131 bir sayfaya y\u00f6nlendirilmek veya bir modal a\u00e7mak kabul edilebilirken, art\u0131k bu t\u00fcr duraklamalar kullan\u0131c\u0131 deneyimi a\u00e7\u0131s\u0131ndan birer engel olarak g\u00f6r\u00fclmektedir. Kullan\u0131c\u0131lar, sosyal medya platformlar\u0131ndan e-ticaret sitelerine kadar her yerde an\u0131nda geri bildirim ve h\u0131zl\u0131 etkile\u015fim aray\u0131\u015f\u0131ndad\u0131r. \u0130\u015fte bu beklentiler, sat\u0131r i\u00e7i d\u00fczenlemeyi sadece bir &#8220;ek \u00f6zellik&#8221; olmaktan \u00e7\u0131kar\u0131p, adeta bir &#8220;zorunluluk&#8221; haline getirmi\u015ftir.<\/p>\n<p>Sat\u0131r i\u00e7i d\u00fczenleme, kullan\u0131c\u0131n\u0131n mevcut i\u00e7erik \u00fczerinde do\u011frudan de\u011fi\u015fiklik yapmas\u0131na olanak tan\u0131r. \u00d6rne\u011fin, bir g\u00f6rev listesindeki bir \u00f6\u011fenin ad\u0131n\u0131 de\u011fi\u015ftirmek, bir e-tablo h\u00fccresindeki de\u011feri g\u00fcncellemek veya bir blog yaz\u0131s\u0131n\u0131n ba\u015fl\u0131\u011f\u0131n\u0131 d\u00fczenlemek gibi i\u015flemler, sayfa yenilemesi olmadan, kullan\u0131c\u0131n\u0131n g\u00f6z\u00fcn\u00fcn \u00f6n\u00fcnde ger\u00e7ekle\u015fir. Bu, ba\u011flam kaybetme sorununu ortadan kald\u0131r\u0131r ve kullan\u0131c\u0131n\u0131n odaklanmas\u0131n\u0131 sa\u011flar. Geleneksel yakla\u015f\u0131mlarda, bir d\u00fczenleme i\u015flemi i\u00e7in ayr\u0131 bir form ekran\u0131na gidildi\u011finde, kullan\u0131c\u0131 mevcut sayfadaki di\u011fer bilgileri g\u00f6zden kaybeder ve bu da bili\u015fsel y\u00fck\u00fc art\u0131r\u0131r. Sat\u0131r i\u00e7i d\u00fczenleme, bu ek ad\u0131mlar\u0131 ortadan kald\u0131rarak i\u015f ak\u0131\u015f\u0131n\u0131 do\u011fal ve ak\u0131c\u0131 hale getirir.<\/p>\n<p>\u00d6zellikle i\u015f uygulamalar\u0131nda, veri giri\u015finin ve d\u00fczenlemesinin yo\u011fun oldu\u011fu durumlarda, sat\u0131r i\u00e7i d\u00fczenleme, \u00e7al\u0131\u015fan verimlili\u011fini \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131rabilir. \u00d6rne\u011fin, bir CRM uygulamas\u0131nda m\u00fc\u015fteri notlar\u0131n\u0131 veya bir envanter y\u00f6netim sisteminde \u00fcr\u00fcn \u00f6zelliklerini h\u0131zl\u0131ca g\u00fcncellemek, kullan\u0131c\u0131lar\u0131n g\u00f6revlerini daha etkin bir \u015fekilde tamamlamas\u0131na yard\u0131mc\u0131 olur. Ayr\u0131ca, bu yakla\u015f\u0131m, uygulaman\u0131n genel tepkiselli\u011fini art\u0131rarak bir Single Page Application (SPA) hissi verir, ancak bunu karma\u015f\u0131k bir frontend \u00e7at\u0131s\u0131na ba\u011fl\u0131 kalmadan ba\u015farabiliriz. Bu sayede, Rails&#8217;in sunucu taraf\u0131ndaki sa\u011flaml\u0131\u011f\u0131n\u0131 ve h\u0131zl\u0131 geli\u015ftirme yeteneklerini korurken, frontend taraf\u0131nda modern bir deneyim sunma esnekli\u011fine sahip oluruz.<\/p>\n<p>Web Components standard\u0131n\u0131n bir par\u00e7as\u0131 olan \u00f6zel elementler (Custom Elements), bu modern etkile\u015fimleri olu\u015fturmak i\u00e7in g\u00fc\u00e7l\u00fc ve standartla\u015ft\u0131r\u0131lm\u0131\u015f bir yol sunar. \u00d6zel elementler, kendi HTML etiketlerimizi tan\u0131mlamam\u0131za, kendi davran\u0131\u015flar\u0131n\u0131 ve stillerini kaps\u00fcllememize olanak tan\u0131r. Bu, yeniden kullan\u0131labilir, okunabilir ve y\u00f6netilebilir bile\u015fenler olu\u015fturmam\u0131z anlam\u0131na gelir. Rails&#8217;in View katman\u0131nda bu \u00f6zel elementleri kullanarak, backend&#8217;den gelen veriyi dinamik olarak g\u00fcncelleyebilen ve kullan\u0131c\u0131 etkile\u015fimlerine an\u0131nda yan\u0131t verebilen etkile\u015fimli aray\u00fczler in\u015fa edebiliriz. Bu, frontend ve backend aras\u0131ndaki ayr\u0131m\u0131 temiz tutarken, her iki d\u00fcnyan\u0131n da en iyi \u00f6zelliklerini bir araya getirir.<\/p>\n<h2>Rails Uygulamalar\u0131nda \u00d6zel Elementlerle Sat\u0131r \u0130\u00e7i D\u00fczenlemeye \u0130lk Ad\u0131m: Temel Kurulumlar<\/h2>\n<p>Rails uygulamalar\u0131n\u0131za \u00f6zel elementler entegre etmek, d\u00fc\u015f\u00fcnd\u00fc\u011f\u00fcn\u00fczden \u00e7ok daha basit. Modern Rails s\u00fcr\u00fcmleri, JavaScript bundler&#8217;lar\u0131 (\u00f6rne\u011fin esbuild) ile sorunsuz bir \u015fekilde entegre olmu\u015ftur, bu da Web Components gibi taray\u0131c\u0131 standartlar\u0131n\u0131 kullanmay\u0131 kolayla\u015ft\u0131r\u0131r. \u0130lk olarak, temiz bir Rails projesiyle veya mevcut bir projenizle ba\u015flayal\u0131m. E\u011fer yeni bir proje olu\u015fturuyorsan\u0131z, a\u015fa\u011f\u0131daki komutla ba\u015flayabilirsiniz:<\/p>\n<pre><code>\nrails new inline_editing_app --css tailwind --javascript esbuild\ncd inline_editing_app\n    <\/pre>\n<p><\/code><\/p>\n<p>Bu komut, Tailwind CSS ve esbuild JavaScript bundler'\u0131 ile yeni bir Rails uygulamas\u0131 olu\u015fturur. esbuild, \u00f6zel elementler i\u00e7in yazd\u0131\u011f\u0131m\u0131z JavaScript kodunu paketlemek ve taray\u0131c\u0131da \u00e7al\u0131\u015fabilir hale getirmek i\u00e7in kullan\u0131lacakt\u0131r. \u00d6zel elementler, standart JavaScript API'leri \u00fczerine in\u015fa edildi\u011fi i\u00e7in ek bir frontend framework'\u00fcne (React, Vue gibi) ihtiyac\u0131n\u0131z yoktur, ancak StimulusJS gibi hafif bir k\u00fct\u00fcphane, daha karma\u015f\u0131k etkile\u015fimleri y\u00f6netmek i\u00e7in m\u00fckemmel bir tamamlay\u0131c\u0131 olabilir. Bu makalede, saf Custom Elements odakl\u0131 bir yakla\u015f\u0131m benimseyece\u011fiz.<\/p>\n<p>Projenizi olu\u015fturduktan sonra, JavaScript dosyalar\u0131n\u0131z\u0131 organize etmek \u00f6nemlidir. Rails 7 ile birlikte gelen <code>app\/javascript<\/code> dizini, bu t\u00fcr dosyalar i\u00e7in ideal bir yerdir. \u00d6zel elementlerimizi bu dizinin alt\u0131nda, \u00f6rne\u011fin <code>app\/javascript\/custom_elements<\/code> \u015feklinde bir klas\u00f6rde tutabiliriz. \u0130lk \u00f6zel elementimizi tan\u0131mlayal\u0131m: Bir metin alan\u0131n\u0131 sat\u0131r i\u00e7i d\u00fczenlenebilir hale getirecek basit bir bile\u015fen.<\/p>\n<p><code>app\/javascript\/custom_elements\/editable_field.js<\/code> dosyas\u0131n\u0131 olu\u015fturun ve i\u00e7ine a\u015fa\u011f\u0131daki temel yap\u0131y\u0131 ekleyin:<\/p>\n<pre><code>\n\/\/ app\/javascript\/custom_elements\/editable_field.js\nclass EditableField extends HTMLElement {\n  constructor() {\n    super(); \/\/ HTMLElement'in constructor'\u0131n\u0131 \u00e7a\u011f\u0131r\u0131yoruz\n    this.attachShadow({ mode: 'open' }); \/\/ Shadow DOM olu\u015fturuyoruz\n    this.isEditing = false;\n  }\n\n  connectedCallback() {\n    \/\/ Element DOM'a eklendi\u011finde \u00e7a\u011fr\u0131l\u0131r\n    this.render();\n  }\n\n  render() {\n    this.shadowRoot.innerHTML = <code><style>\n        .editable-container {\n          display: flex;\n          align-items: center;\n          gap: 8px;\n        }\n        .display-mode {\n          cursor: pointer;\n          padding: 4px 8px;\n          border-radius: 4px;\n        }\n        .display-mode:hover {\n          background-color: #f0f0f0;\n        }\n        .edit-mode input {\n          border: 1px solid #ccc;\n          padding: 4px 8px;\n          border-radius: 4px;\n          font-size: 1em;\n        }\n        .save-button {\n          background-color: #4CAF50;\n          color: white;\n          border: none;\n          padding: 6px 12px;\n          border-radius: 4px;\n          cursor: pointer;\n        }\n        .cancel-button {\n          background-color: #f44336;\n          color: white;\n          border: none;\n          padding: 6px 12px;\n          border-radius: 4px;\n          cursor: pointer;\n        }\n      <\/style>\n      <div class=\"editable-container\">\n        ${this.isEditing ? this.renderEditMode() : this.renderDisplayMode()}\n      <\/div><\/code>;\n\n    if (this.isEditing) {\n      this.shadowRoot.querySelector('input').focus();\n      this.shadowRoot.querySelector('input').select();\n    }\n    this.addEventListeners();\n  }\n\n  renderDisplayMode() {\n    return <code><span class=\"display-mode\">${this.getAttribute(&#039;value&#039;)}<\/span><\/code>;\n  }\n\n  renderEditMode() {\n    return <code><div class=\"edit-mode\">\n        <input type=\"text\" value=\"${this.getAttribute(&#039;value&#039;)}\" \/>\n        <button class=\"save-button\">Kaydet<\/button>\n        <button class=\"cancel-button\">\u0130ptal<\/button>\n      <\/div><\/code>;\n  }\n\n  addEventListeners() {\n    if (!this.isEditing) {\n      this.shadowRoot.querySelector('.display-mode').addEventListener('click', () => {\n        this.isEditing = true;\n        this.render();\n      });\n    } else {\n      const input = this.shadowRoot.querySelector('input');\n      const saveButton = this.shadowRoot.querySelector('.save-button');\n      const cancelButton = this.shadowRoot.querySelector('.cancel-button');\n\n      saveButton.addEventListener('click', () => this.saveChanges(input.value));\n      cancelButton.addEventListener('click', () => this.cancelChanges());\n      input.addEventListener('keydown', (e) => {\n        if (e.key === 'Enter') {\n          this.saveChanges(input.value);\n        } else if (e.key === 'Escape') {\n          this.cancelChanges();\n        }\n      });\n      input.addEventListener('blur', (e) => {\n        \/\/ Blur olay\u0131, kaydet veya iptal butonuna t\u0131klan\u0131nca da tetiklenebilir.\n        \/\/ Bu durumu y\u00f6netmek i\u00e7in timeout kullanabiliriz veya ilgili butonlar\u0131n click olaylar\u0131n\u0131n\n        \/\/ blur'dan \u00f6nce tetiklendi\u011finden emin olabiliriz. \u015eimdilik basitiyle devam edelim.\n        \/\/ e.relatedTarget, blur olan elementten sonra focus'un gitti\u011fi elementi verir.\n        \/\/ E\u011fer focus, save\/cancel butonlar\u0131na gittiyse, blur'da otomatik iptal etmeyiz.\n        if (e.relatedTarget !== saveButton && e.relatedTarget !== cancelButton) {\n          \/\/ this.cancelChanges(); \/\/ Otomatik iptal etmek istemiyorsan\u0131z bu sat\u0131r\u0131 yorumda b\u0131rak\u0131n\n        }\n      });\n    }\n  }\n\n  saveChanges(newValue) {\n    this.setAttribute('value', newValue); \/\/ \u015eimdilik sadece attribute'\u00fc g\u00fcncelliyoruz\n    this.dispatchEvent(new CustomEvent('change', { detail: { value: newValue } }));\n    this.isEditing = false;\n    this.render();\n  }\n\n  cancelChanges() {\n    this.isEditing = false;\n    this.render();\n  }\n}\n\ncustomElements.define('editable-field', EditableField);\n    <\/pre>\n<p><\/code><\/p>\n<p>Yukar\u0131daki kodda, <code>EditableField<\/code> ad\u0131nda bir \u00f6zel element tan\u0131mlad\u0131k. Bu element, <code>value<\/code> ad\u0131nda bir attribute al\u0131r ve bu de\u011feri g\u00f6sterir. \u00dczerine t\u0131kland\u0131\u011f\u0131nda d\u00fczenleme moduna ge\u00e7er ve bir input alan\u0131 ile \"Kaydet\" ve \"\u0130ptal\" butonlar\u0131 g\u00f6sterir. De\u011fi\u015fiklikler kaydedildi\u011finde veya iptal edildi\u011finde tekrar g\u00f6r\u00fcnt\u00fcleme moduna d\u00f6ner. <code>attachShadow({ mode: 'open' })<\/code> sat\u0131r\u0131 ile Shadow DOM olu\u015fturduk. Bu, \u00f6zel elementin i\u00e7 CSS ve JavaScript'inin d\u0131\u015f d\u00fcnyadan izole olmas\u0131n\u0131 sa\u011flar, b\u00f6ylece global stil \u00e7ak\u0131\u015fmalar\u0131n\u0131n \u00f6n\u00fcne ge\u00e7ilir ve element kendi kendine yeterli bir birim haline gelir.<\/p>\n<p>Bu \u00f6zel elementi Rails uygulaman\u0131za dahil etmek i\u00e7in, <code>app\/javascript\/application.js<\/code> dosyan\u0131zda bunu import etmeniz yeterlidir:<\/p>\n<pre><code>\n\/\/ app\/javascript\/application.js\nimport \"@hotwired\/turbo-rails\"\nimport \"controllers\"\nimport \".\/custom_elements\/editable_field\" \/\/ Yeni ekledi\u011fimiz sat\u0131r\n    <\/pre>\n<p><\/code><\/p>\n<p>Art\u0131k uygulaman\u0131z\u0131n herhangi bir View dosyas\u0131nda <code><editable-field><\/code> etiketini kullanabilirsiniz. \u00d6rne\u011fin, <code>app\/views\/posts\/show.html.erb<\/code> dosyas\u0131nda:<\/p>\n<pre><code>\n<h2>Ba\u015fl\u0131k: <editable-field value=\"<%= @post.title %>\"><\/editable-field><\/h2>\n    <\/pre>\n<p><\/code><\/p>\n<p>Bu ad\u0131mlar, \u00f6zel elementlerin temelini olu\u015fturman\u0131z i\u00e7in size yol g\u00f6sterecektir. Ancak, bu elementin hen\u00fcz Rails backend'i ile bir ileti\u015fim kurmad\u0131\u011f\u0131n\u0131 unutmay\u0131n. Sonraki b\u00f6l\u00fcmde, bu elementin nas\u0131l dinamik olarak veri g\u00fcncelleyebilece\u011fini ve Rails ile nas\u0131l entegre olaca\u011f\u0131n\u0131 inceleyece\u011fiz. Bu temel kurulum sayesinde, art\u0131k projenizde kendi \u00f6zel HTML bile\u015fenlerinizi olu\u015fturman\u0131n ve bunlar\u0131 uygulaman\u0131z\u0131n farkl\u0131 yerlerinde tekrar kullanman\u0131n kap\u0131s\u0131n\u0131 aralam\u0131\u015f olursunuz. Her bir \u00f6zel element, kendi mant\u0131\u011f\u0131na ve stiline sahip ba\u011f\u0131ms\u0131z bir birim olarak hareket edebilir, bu da kod taban\u0131n\u0131z\u0131n mod\u00fclerli\u011fini ve s\u00fcrd\u00fcr\u00fclebilirli\u011fini art\u0131r\u0131r.<\/p>\n<h2>Etkile\u015fimli Sat\u0131r \u0130\u00e7i D\u00fczenleme Bile\u015fenleri Nas\u0131l Olu\u015fturulur? Pratik Bir \u00d6rnek<\/h2>\n<p>Bir \u00f6nceki b\u00f6l\u00fcmde temel bir <code><editable-field><\/code> \u00f6zel elementini tan\u0131mlam\u0131\u015ft\u0131k. \u015eimdi bu elementi ger\u00e7ek d\u00fcnya senaryolar\u0131na uygun hale getirelim ve bir Rails backend'i ile etkile\u015fime sokal\u0131m. En yayg\u0131n senaryolardan biri, bir veri modelinin (\u00f6rne\u011fin, bir <code>Post<\/code> veya <code>Product<\/code>) belirli bir \u00f6zniteli\u011fini sat\u0131r i\u00e7i olarak d\u00fczenlemektir. Bu, kullan\u0131c\u0131n\u0131n bir g\u00f6nderi ba\u015fl\u0131\u011f\u0131n\u0131 veya bir \u00fcr\u00fcn a\u00e7\u0131klamas\u0131n\u0131 do\u011frudan listede veya detay sayfas\u0131nda d\u00fczenlemesini sa\u011flar.<\/p>\n<p>\u00d6ncelikle, Rails taraf\u0131nda bir <code>Post<\/code> modeline ve onu d\u00fczenleyecek bir controller'a ihtiyac\u0131m\u0131z var. E\u011fer yoksa, yeni bir scaffold olu\u015fturarak ba\u015flayabiliriz:<\/p>\n<pre><code>\nrails g scaffold Post title:string content:text\nrails db:migrate\n    <\/pre>\n<p><\/code><\/p>\n<p>Bu komutlar, <code>Post<\/code> modelini, migration dosyas\u0131n\u0131, controller'\u0131 ve view dosyalar\u0131n\u0131 olu\u015fturacakt\u0131r. \u015eimdi, <code>PostsController<\/code>'da, sat\u0131r i\u00e7i d\u00fczenleme ile gelen g\u00fcncellemeyi i\u015fleyecek bir <code>update<\/code> aksiyonuna ihtiyac\u0131m\u0131z var. Genellikle, bu t\u00fcr AJAX istekleri i\u00e7in sadece belirli bir \u00f6zniteli\u011fi g\u00fcncelleyen hafif bir cevap bekleriz.<\/p>\n<pre><code>\n# app\/controllers\/posts_controller.rb\nclass PostsController < ApplicationController\n  before_action :set_post, only: %i[ show edit update destroy ]\n\n  # ... di\u011fer aksiyonlar ...\n\n  def update\n    respond_to do |format|\n      if @post.update(post_params)\n        format.html { redirect_to post_url(@post), notice: \"Post was successfully updated.\" }\n        format.json { render json: { value: @post.title, success: true }, status: :ok } # AJAX i\u00e7in\n      else\n        format.html { render :edit, status: :unprocessable_entity }\n        format.json { render json: @post.errors, status: :unprocessable_entity } # AJAX i\u00e7in hata\n      end\n    end\n  end\n\n  # ... di\u011fer aksiyonlar ...\n\n  private\n    def set_post\n      @post = Post.find(params[:id])\n    end\n\n    def post_params\n      params.require(:post).permit(:title, :content)\n    end\nend\n    <\/pre>\n<p><\/code><\/p>\n<p>Yukar\u0131daki <code>update<\/code> aksiyonunda, <code>format.json<\/code> blo\u011funu ekledik. Bu blok, AJAX iste\u011fi geldi\u011finde g\u00fcncellenen de\u011feri ve bir ba\u015far\u0131 durumunu JSON olarak d\u00f6nd\u00fcr\u00fcr. Bu, \u00f6zel elementimizin backend ile ileti\u015fim kurdu\u011funda alaca\u011f\u0131 cevapt\u0131r.<\/p>\n<p>\u015eimdi <code>editable_field.js<\/code> dosyam\u0131z\u0131 g\u00fcncelleyelim. Elementimizin, hangi modelin hangi \u00f6zniteli\u011fini g\u00fcncelleyece\u011fini ve hangi URL'ye istek g\u00f6nderece\u011fini bilmesi gerekiyor. Bunun i\u00e7in, elementimize yeni attribute'ler ekleyece\u011fiz: <code>resource-url<\/code> (API endpoint'i) ve <code>attribute-name<\/code> (g\u00fcncellenecek \u00f6znitelik).<\/p>\n<pre><code>\n\/\/ app\/javascript\/custom_elements\/editable_field.js (G\u00fcncellenmi\u015f Versiyon)\nclass EditableField extends HTMLElement {\n  static get observedAttributes() {\n    return ['value', 'resource-url', 'attribute-name', 'resource-id'];\n  }\n\n  constructor() {\n    super();\n    this.attachShadow({ mode: 'open' });\n    this.isEditing = false;\n    this.initialValue = this.getAttribute('value');\n  }\n\n  attributeChangedCallback(name, oldValue, newValue) {\n    if (name === 'value' && oldValue !== newValue && this.shadowRoot) {\n      this.initialValue = newValue; \/\/ Yeni de\u011feri initialValue olarak da sakla\n      if (!this.isEditing) { \/\/ Sadece d\u00fczenleme modunda de\u011filken render et\n        this.render();\n      }\n    }\n  }\n\n  connectedCallback() {\n    this.render();\n  }\n\n  render() {\n    \/\/ ... (\u00d6nceki render() fonksiyonundaki stil ve genel yap\u0131 ayn\u0131 kalacak) ...\n    this.shadowRoot.innerHTML = <code><style>\n        \/* \u00d6nceki stil kodlar\u0131 *\/\n        .editable-container { display: flex; align-items: center; gap: 8px; }\n        .display-mode { cursor: pointer; padding: 4px 8px; border-radius: 4px; }\n        .display-mode:hover { background-color: #f0f0f0; }\n        .edit-mode input { border: 1px solid #ccc; padding: 4px 8px; border-radius: 4px; font-size: 1em; }\n        .save-button { background-color: #4CAF50; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; }\n        .cancel-button { background-color: #f44336; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; }\n        .loading-spinner {\n          border: 2px solid #f3f3f3;\n          border-top: 2px solid #3498db;\n          border-radius: 50%;\n          width: 12px;\n          height: 12px;\n          animation: spin 1s linear infinite;\n          display: inline-block;\n          margin-left: 5px;\n          vertical-align: middle;\n        }\n        @keyframes spin {\n          0% { transform: rotate(0deg); }\n          100% { transform: rotate(360deg); }\n        }\n      <\/style>\n      <div class=\"editable-container\">\n        ${this.isEditing ? this.renderEditMode() : this.renderDisplayMode()}\n        ${this.isLoading ?<\/code><div class=\"loading-spinner\"><\/div><code>: &#039;&#039;}\n      <\/div><\/code>;\n\n    if (this.isEditing) {\n      const input = this.shadowRoot.querySelector('input');\n      if (input) {\n        input.focus();\n        input.select();\n      }\n    }\n    this.addEventListeners();\n  }\n\n  renderDisplayMode() {\n    return <code><span class=\"display-mode\">${this.getAttribute(&#039;value&#039;) || &#039;&#039;}<\/span><\/code>;\n  }\n\n  renderEditMode() {\n    return <code><div class=\"edit-mode\">\n        <input type=\"text\" value=\"${this.getAttribute(&#039;value&#039;) || &#039;&#039;}\" \/>\n        <button class=\"save-button\">Kaydet<\/button>\n        <button class=\"cancel-button\">\u0130ptal<\/button>\n      <\/div><\/code>;\n  }\n\n  addEventListeners() {\n    \/\/ \u00d6nceki event listener'lar...\n    if (!this.isEditing) {\n      const displayMode = this.shadowRoot.querySelector('.display-mode');\n      if (displayMode) {\n        displayMode.addEventListener('click', () => {\n          this.isEditing = true;\n          this.render();\n        });\n      }\n    } else {\n      const input = this.shadowRoot.querySelector('input');\n      const saveButton = this.shadowRoot.querySelector('.save-button');\n      const cancelButton = this.shadowRoot.querySelector('.cancel-button');\n\n      if (saveButton) saveButton.addEventListener('click', () => this.saveChanges(input.value));\n      if (cancelButton) cancelButton.addEventListener('click', () => this.cancelChanges());\n      if (input) {\n        input.addEventListener('keydown', (e) => {\n          if (e.key === 'Enter') {\n            this.saveChanges(input.value);\n          } else if (e.key === 'Escape') {\n            this.cancelChanges();\n          }\n        });\n        input.addEventListener('blur', (e) => {\n          \/\/ E\u011fer focus, save\/cancel butonlar\u0131na gittiyse otomatik iptal etme\n          if (e.relatedTarget !== saveButton && e.relatedTarget !== cancelButton) {\n            \/\/ this.cancelChanges(); \/\/ \u0130ste\u011fe ba\u011fl\u0131: Blur oldu\u011funda iptal et\n          }\n        });\n      }\n    }\n  }\n\n  async saveChanges(newValue) {\n    if (newValue === this.initialValue) {\n        this.isEditing = false;\n        this.render();\n        return; \/\/ De\u011fer de\u011fi\u015fmediyse AJAX iste\u011fi g\u00f6nderme\n    }\n\n    this.isLoading = true; \/\/ Y\u00fckleniyor durumunu ayarla\n    this.render(); \/\/ Spinner'\u0131 g\u00f6stermek i\u00e7in yeniden render et\n\n    const resourceUrl = this.getAttribute('resource-url');\n    const attributeName = this.getAttribute('attribute-name');\n    const resourceId = this.getAttribute('resource-id');\n\n    if (!resourceUrl || !attributeName || !resourceId) {\n      console.error('resource-url, attribute-name veya resource-id attribute\\'leri eksik!');\n      this.isLoading = false;\n      this.render();\n      return;\n    }\n\n    const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').getAttribute('content');\n\n    try {\n      const response = await fetch(<code>${resourceUrl}\/${resourceId}<\/code>, {\n        method: 'PATCH',\n        headers: {\n          'Content-Type': 'application\/json',\n          'X-CSRF-Token': csrfToken,\n          'Accept': 'application\/json'\n        },\n        body: JSON.stringify({\n          [attributeName]: newValue,\n          \/\/ Rails'in strong parameters i\u00e7in resource_name: { attribute_name: value } yap\u0131s\u0131n\u0131 bekledi\u011fini unutmay\u0131n\n          \/\/ Bu \u00f6rnekte, 'post' veya 'product' gibi bir resource_name'i dinamik olarak almad\u0131\u011f\u0131m\u0131z i\u00e7in\n          \/\/ attributeName'i do\u011frudan kullan\u0131yoruz. Daha robust bir \u00e7\u00f6z\u00fcm i\u00e7in,\n          \/\/ resource-name attribute'\u00fc de eklenebilir.\n          \/\/ E\u011fer resource_name'i dinamik olarak almak istiyorsan\u0131z:\n          \/\/ [this.getAttribute('resource-name')]: { [attributeName]: newValue }\n        })\n      });\n\n      if (!response.ok) {\n        throw new Error(<code>HTTP error! status: ${response.status}<\/code>);\n      }\n\n      const data = await response.json();\n      this.setAttribute('value', data.value); \/\/ Backend'den gelen g\u00fcncel de\u011feri ayarla\n      this.initialValue = data.value; \/\/ Ba\u015flang\u0131\u00e7 de\u011ferini de g\u00fcncelle\n      this.dispatchEvent(new CustomEvent('change', { detail: { value: data.value, success: true } }));\n    } catch (error) {\n      console.error('De\u011fi\u015fiklikler kaydedilirken hata olu\u015ftu:', error);\n      this.dispatchEvent(new CustomEvent('change', { detail: { value: this.initialValue, success: false, error: error.message } }));\n      \/\/ Hata durumunda, eski de\u011fere geri d\u00f6nebilir veya kullan\u0131c\u0131ya bilgi verebilirsiniz\n      this.setAttribute('value', this.initialValue); \/\/ Hata durumunda orijinal de\u011feri geri y\u00fckle\n    } finally {\n      this.isLoading = false;\n      this.isEditing = false;\n      this.render();\n    }\n  }\n\n  cancelChanges() {\n    this.setAttribute('value', this.initialValue); \/\/ Ba\u015flang\u0131\u00e7 de\u011ferine geri d\u00f6n\n    this.isEditing = false;\n    this.render();\n  }\n}\n\ncustomElements.define('editable-field', EditableField);\n    <\/pre>\n<p><\/code><\/p>\n<p>Bu g\u00fcncellemelerle birlikte, <code>saveChanges<\/code> metodu art\u0131k bir <code>fetch<\/code> API iste\u011fi g\u00f6ndererek Rails backend'i ile ileti\u015fim kuruyor. <code>PATCH<\/code> metodu kullanarak belirli bir kayna\u011f\u0131 g\u00fcncelliyor ve CSRF token'\u0131n\u0131 ba\u015fl\u0131klar aras\u0131na ekleyerek Rails'in g\u00fcvenlik kontrollerini ge\u00e7iyor. <code>resource-url<\/code>, <code>attribute-name<\/code> ve <code>resource-id<\/code> attribute'leri sayesinde element, hangi veriyi nerede g\u00fcncelleyece\u011fini biliyor. Ayr\u0131ca, kullan\u0131c\u0131ya i\u015flem s\u0131ras\u0131nda g\u00f6rsel geri bildirim sa\u011flamak i\u00e7in bir y\u00fcklenme spinner'\u0131 (<code>loading-spinner<\/code>) ekledik ve <code>isLoading<\/code> durumunu y\u00f6netiyoruz.<\/p>\n<p>\u015eimdi <code>app\/views\/posts\/show.html.erb<\/code> dosyam\u0131z\u0131 g\u00fcncelleyerek bu yeni elementimizi kullanal\u0131m:<\/p>\n<pre><code>\n<!-- app\/views\/posts\/show.html.erb -->\n<p style=\"color: green\"><%= notice %><\/p>\n\n<h1>G\u00f6nderi Detay\u0131<\/h1>\n\n<div>\n  <strong>Ba\u015fl\u0131k:<\/strong>\n  <editable-field\n    value=\"<%= @post.title %>\"\n    resource-url=\"<%= posts_url %>\"\n    attribute-name=\"post[title]\"\n    resource-id=\"<%= @post.id %>\"\n  ><\/editable-field>\n<\/div>\n\n<div>\n  <strong>\u0130\u00e7erik:<\/strong>\n  <editable-field\n    value=\"<%= @post.content %>\"\n    resource-url=\"<%= posts_url %>\"\n    attribute-name=\"post[content]\"\n    resource-id=\"<%= @post.id %>\"\n  ><\/editable-field>\n<\/div>\n\n<div>\n  <%= link_to \"D\u00fczenle\", edit_post_path(@post) %> |\n  <%= link_to \"Geri\", posts_path %>\n\n  <%= button_to \"Sil\", @post, method: :delete %>\n<\/div>\n    <\/pre>\n<p><\/code><\/p>\n<p>Burada <code>attribute-name=\"post[title]\"<\/code> \u015feklinde bir de\u011fer kulland\u0131k \u00e7\u00fcnk\u00fc Rails'in Strong Parameters mekanizmas\u0131 genellikle bu formatta veri bekler (\u00f6rne\u011fin <code>params[:post][:title]<\/code>). Bu yap\u0131 sayesinde, \u00f6zel elementimiz art\u0131k Rails backend'i ile tam entegre bir \u015fekilde \u00e7al\u0131\u015f\u0131yor. Kullan\u0131c\u0131lar art\u0131k sayfa yenilemeden veya farkl\u0131 bir forma gitmeden g\u00f6nderi ba\u015fl\u0131\u011f\u0131n\u0131 ve i\u00e7eri\u011fini do\u011frudan g\u00f6rebilecekleri yerden d\u00fczenleyebilirler. Bu, \u00f6zellikle veri yo\u011fun uygulamalarda veya y\u00f6netim panellerinde b\u00fcy\u00fck bir kolayl\u0131k ve h\u0131z sa\u011flar. B\u00f6ylece, kullan\u0131c\u0131lar\u0131n\u0131z\u0131n uygulaman\u0131zla olan etkile\u015fimini daha ak\u0131c\u0131 ve kesintisiz hale getirmi\u015f olursunuz.<\/p>\n<h2>Geli\u015fmi\u015f Kullan\u0131m Senaryolar\u0131 ve Performans \u0130yile\u015ftirmeleri<\/h2>\n<p>\u00d6zel elementlerle sat\u0131r i\u00e7i d\u00fczenleme, temel bir \u00f6zellik olman\u0131n \u00f6tesine ge\u00e7erek uygulaman\u0131za ciddi avantajlar sa\u011flayabilir. Ancak, her zaman oldu\u011fu gibi, daha iyi bir kullan\u0131c\u0131 deneyimi ve daha optimize edilmi\u015f bir performans i\u00e7in baz\u0131 ileri d\u00fczey tekniklere ve ipu\u00e7lar\u0131na ihtiya\u00e7 duyabiliriz. Bu b\u00f6l\u00fcmde, \u00f6zel elementlerinizi daha g\u00fc\u00e7l\u00fc ve verimli hale getirecek baz\u0131 senaryolar\u0131 ve iyile\u015ftirme y\u00f6ntemlerini ele alaca\u011f\u0131z.<\/p>\n<p><strong>1. Gecikmeli Kay\u0131t (Debouncing Input):<\/strong> Kullan\u0131c\u0131 bir metin alan\u0131na yazarken her karakter giri\u015finde backend'e istek g\u00f6ndermek, sunucu \u00fczerinde gereksiz y\u00fck olu\u015fturabilir ve a\u011f trafi\u011fini art\u0131rabilir. \u00d6zellikle uzun metin alanlar\u0131nda bu durum daha belirgin hale gelir. Bu t\u00fcr senaryolar i\u00e7in \"debouncing\" tekni\u011fini kullanabiliriz. Debouncing, belirli bir s\u00fcre boyunca (\u00f6rne\u011fin 300-500ms) ba\u015fka bir olay\u0131n tetiklenmemesi durumunda bir fonksiyonu \u00e7al\u0131\u015ft\u0131rmak anlam\u0131na gelir. B\u00f6ylece, kullan\u0131c\u0131 yazmay\u0131 b\u0131rakt\u0131\u011f\u0131nda veya duraklad\u0131\u011f\u0131nda kay\u0131t i\u015flemi tetiklenir.<\/p>\n<pre><code>\n\/\/ app\/javascript\/custom_elements\/editable_field.js i\u00e7ine eklenecek veya mevcut saveChanges'i g\u00fcncelleyecek k\u0131s\u0131m\n\/\/ Debounce fonksiyonu\nfunction debounce(func, delay) {\n  let timeout;\n  return function(...args) {\n    const context = this;\n    clearTimeout(timeout);\n    timeout = setTimeout(() => func.apply(context, args), delay);\n  };\n}\n\n\/\/ EditableField s\u0131n\u0131f\u0131n\u0131n i\u00e7inde:\n\/\/ constructor i\u00e7inde:\nthis.debouncedSave = debounce(this._performSave, 500); \/\/ 500ms gecikme\n\n\/\/ input event listener'\u0131n\u0131 g\u00fcncelle:\n\/\/ input.addEventListener('input', (e) => this.debouncedSave(e.target.value)); \/\/ E\u011fer otomatik kaydetme istiyorsan\u0131z\n\/\/ Mevcut Save butonu click olay\u0131nda ise do\u011frudan _performSave \u00e7a\u011f\u0131rabilirsiniz.\n\n\/\/ Yeni bir _performSave metodu olu\u015ftur:\nasync _performSave(newValue) {\n    \/\/ Mevcut saveChanges i\u00e7indeki t\u00fcm AJAX ve durum y\u00f6netimi buraya ta\u015f\u0131n\u0131r\n    \/\/ ... fetch iste\u011fi, loading spinner, isEditing = false, render() vs. ...\n}\n\n\/\/ saveChanges'i _performSave \u00e7a\u011f\u0131racak \u015fekilde g\u00fcncelleyebilirsiniz veya sadece Enter\/Kaydet butonuna odaklanabilirsiniz.\nasync saveChanges(newValue) {\n  this.debouncedSave(newValue);\n}\n    <\/pre>\n<p><\/code><\/p>\n<p>Bu yakla\u015f\u0131m, klavye giri\u015fi s\u0131ras\u0131nda backend isteklerinin say\u0131s\u0131n\u0131 \u00f6nemli \u00f6l\u00e7\u00fcde azalt\u0131r ve sunucu \u00fczerindeki y\u00fck\u00fc hafifletir. Kullan\u0131c\u0131 deneyimi a\u00e7\u0131s\u0131ndan da daha ak\u0131c\u0131 bir his verir, \u00e7\u00fcnk\u00fc her tu\u015fa bas\u0131\u015fta an\u0131nda bir \"kaydediliyor...\" mesaj\u0131 g\u00f6rmek yerine, sadece yaz\u0131 durdu\u011funda bu geri bildirimi al\u0131rlar.<\/p>\n<p><strong>2. Sunucu Taraf\u0131 Render (SSR) ve \u0130stemci Taraf\u0131 Hidrasyon:<\/strong> Rails varsay\u0131lan olarak sunucu taraf\u0131nda HTML \u00fcretir. \u00d6zel elementleri bu SSR ak\u0131\u015f\u0131na dahil etmek, ilk sayfa y\u00fcklemesinde i\u00e7eri\u011fin hemen g\u00f6r\u00fcn\u00fcr olmas\u0131n\u0131 sa\u011flar (daha iyi SEO ve ilk y\u00fckleme performans\u0131). \u0130stemci taraf\u0131nda ise JavaScript, bu statik HTML \u00fczerinde \"hidrasyon\" yaparak \u00f6zel elementleri etkile\u015fimli hale getirir. Yani, ilk y\u00fcklemede <code><editable-field value=\"Merhaba\"><\/editable-field><\/code> etiketi taray\u0131c\u0131ya ula\u015f\u0131r ve taray\u0131c\u0131 JavaScript'i \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131nda bu etiket bir Custom Element \u00f6rne\u011fine d\u00f6n\u00fc\u015f\u00fcr. Bu, \u00f6zellikle b\u00fcy\u00fck ve karma\u015f\u0131k uygulamalarda ba\u015flang\u0131\u00e7 performans\u0131n\u0131 art\u0131rmak i\u00e7in kritik bir tekniktir.<\/p>\n<blockquote><p>\n      Uzman \u0130pucu: Web Components ile Shadow DOM kulland\u0131\u011f\u0131n\u0131zda, CSS stilleri varsay\u0131lan olarak kaps\u00fcllenir. Ancak, d\u0131\u015far\u0131dan veya i\u00e7eriden stiller \u00fczerinde tam kontrol sa\u011flamak i\u00e7in CSS Custom Properties (CSS De\u011fi\u015fkenleri) kullanabilirsiniz. \u00d6rne\u011fin, Shadow DOM i\u00e7inde <code>var(--editable-field-bg, #f0f0f0)<\/code> tan\u0131mlayarak, ana belge stillerinden <code>--editable-field-bg: lightblue;<\/code> ile rengi de\u011fi\u015ftirebilirsiniz. Bu teknikle, \u00f6zel elementlerinizin g\u00f6rsel entegrasyonunu \u00e7ok daha esnek hale getirebilirsiniz.\n    <\/p><\/blockquote>\n<p><strong>3. Eri\u015filebilirlik (Accessibility - A11y) Odakl\u0131 Tasar\u0131m:<\/strong> Sat\u0131r i\u00e7i d\u00fczenleme, genellikle klavye kullan\u0131c\u0131lar\u0131 veya ekran okuyucu kullananlar i\u00e7in ek zorluklar yaratabilir. \u00d6zel elementlerinizi tasarlarken, ARIA (Accessible Rich Internet Applications) niteliklerini kullanmay\u0131 unutmay\u0131n. \u00d6rne\u011fin, d\u00fczenleme moduna ge\u00e7ildi\u011finde input alan\u0131na <code>aria-label<\/code> eklemek, kullan\u0131c\u0131ya neyi d\u00fczenledi\u011fini a\u00e7\u0131k\u00e7a belirtmek ve odak y\u00f6netimini do\u011fru yapmak \u00f6nemlidir. D\u00fczenleme moduna girildi\u011finde odak otomatik olarak input alan\u0131na gitmeli, kaydedildi\u011finde veya iptal edildi\u011finde ise orijinal g\u00f6r\u00fcnt\u00fcleme eleman\u0131na geri d\u00f6nmelidir. Bu, t\u00fcm kullan\u0131c\u0131lar\u0131n uygulaman\u0131z\u0131 sorunsuz bir \u015fekilde kullanabilmesini sa\u011flar.<\/p>\n<p><strong>4. Entegrasyon ve Test:<\/strong> \u00d6zel elementler, di\u011fer JavaScript k\u00fct\u00fcphaneleri veya Rails'in Hotwire (Turbo, Stimulus) ekosistemi ile sorunsuz bir \u015fekilde \u00e7al\u0131\u015fabilir. \u00d6rne\u011fin, bir Turbo Frame i\u00e7inde bir <code><editable-field><\/code> kullanmak, par\u00e7al\u0131 g\u00fcncellemeleri y\u00f6netmeyi kolayla\u015ft\u0131r\u0131r. Test taraf\u0131nda ise, \u00f6zel elementlerinizi hem birim testleriyle (\u00f6rne\u011fin Jest ile) hem de entegrasyon testleriyle (\u00f6rne\u011fin Capybara ile Rails system testleri) test etmek, hatalar\u0131 erken yakalaman\u0131za yard\u0131mc\u0131 olur. Capybara, DOM'daki \u00f6zel elementlerle etkile\u015fim kurman\u0131za izin verir, t\u0131pk\u0131 standart HTML elementleri gibi.<\/p>\n<p><strong>Vaka Analizi: E-Ticaret Platformunda \u00dcr\u00fcn A\u00e7\u0131klamas\u0131 D\u00fczenleme<\/strong><\/p>\n<p>B\u00fcy\u00fck bir e-ticaret platformunun y\u00f6netim panelinde, \u00fcr\u00fcn y\u00f6neticilerinin binlerce \u00fcr\u00fcn\u00fcn a\u00e7\u0131klamas\u0131n\u0131, fiyat\u0131n\u0131 ve stok durumunu h\u0131zl\u0131ca g\u00fcncellemesi gerekmektedir. Geleneksel yakla\u015f\u0131mla, her \u00fcr\u00fcn i\u00e7in ayr\u0131 bir d\u00fczenleme sayfas\u0131na gitmek ve kaydetmek, ciddi bir zaman kayb\u0131na yol a\u00e7maktad\u0131r. Bu sorunu \u00e7\u00f6zmek i\u00e7in \u00f6zel elementler ve sat\u0131r i\u00e7i d\u00fczenleme kullan\u0131lm\u0131\u015ft\u0131r.<\/p>\n<p>Her \u00fcr\u00fcn listeleme sayfas\u0131ndaki \u00fcr\u00fcn a\u00e7\u0131klamas\u0131 ve fiyat\u0131, <code><product-editable-field><\/code> \u00f6zel elementi ile sarmalanm\u0131\u015ft\u0131r. Bu element, kullan\u0131c\u0131n\u0131n \u00fczerine t\u0131klad\u0131\u011f\u0131nda bir metin alan\u0131 veya say\u0131sal bir input g\u00f6stermekte ve de\u011fi\u015fiklikler yap\u0131ld\u0131\u011f\u0131nda otomatik olarak arka planda <code>PATCH<\/code> iste\u011fi ile Rails backend'ine g\u00f6nderilmektedir. Debouncing tekni\u011fi, a\u00e7\u0131klama gibi uzun metin alanlar\u0131nda gereksiz istekleri engellemektedir.<\/p>\n<p>Sonu\u00e7 olarak, \u00fcr\u00fcn y\u00f6neticileri art\u0131k y\u00fczlerce \u00fcr\u00fcn\u00fc tek bir sayfada h\u0131zl\u0131ca taray\u0131p gerekli de\u011fi\u015fiklikleri an\u0131nda yapabilmekte, bu da operasyonel verimlili\u011fi %40'\u0131n \u00fczerinde art\u0131rm\u0131\u015ft\u0131r. Ayr\u0131ca, bu \u00f6zellik sayesinde kullan\u0131c\u0131lar, karma\u015f\u0131k formlarla u\u011fra\u015fmak zorunda kalmadan, daha ak\u0131c\u0131 ve sezgisel bir deneyim ya\u015fam\u0131\u015ft\u0131r. Performans a\u00e7\u0131s\u0131ndan da, sadece de\u011fi\u015fen verinin g\u00f6nderilmesi ve sayfa yenilenmemesi, sunucu y\u00fck\u00fcn\u00fc ve a\u011f trafi\u011fini \u00f6nemli \u00f6l\u00e7\u00fcde azaltm\u0131\u015ft\u0131r.<\/p>\n<h3>\u00d6zel Elementlerinizi Mobil Uyumlu Hale Getirmek: Media Query \u00d6rnekleri<\/h3>\n<p>Mobil uyumluluk (responsive design), g\u00fcn\u00fcm\u00fcz web geli\u015ftirmesinde vazge\u00e7ilmez bir unsurdur. \u00d6zel elementler, Shadow DOM ile kendi stillerini kaps\u00fcllese de, mobil cihazlarda farkl\u0131 g\u00f6r\u00fcnmesi veya davranmas\u0131 gereken durumlarda <code>@media<\/code> kurallar\u0131ndan faydalanabilir. Bir \u00f6zel elementin i\u00e7inde, t\u0131pk\u0131 bir HTML belgesinde oldu\u011fu gibi, kendi stillerini tan\u0131mlayabilir ve bu stilleri ekran boyutuna g\u00f6re de\u011fi\u015ftirebilirsiniz.<\/p>\n<p>\u00d6rne\u011fin, <code>editable-field<\/code> elementimizin mobil cihazlarda daha b\u00fcy\u00fck bir yaz\u0131 tipi kullanmas\u0131n\u0131 veya d\u00fczenleme modunda butonlar\u0131n tam geni\u015flikte olmas\u0131n\u0131 isteyebiliriz. Shadow DOM i\u00e7indeki <code><\/p>\n<style><\/code> etiketine a\u015fa\u011f\u0131daki gibi <code>@media<\/code> kurallar\u0131 ekleyebiliriz:<\/p>\n<pre><code>\n\/\/ app\/javascript\/custom_elements\/editable_field.js (Stil B\u00f6l\u00fcm\u00fc G\u00fcncellendi)\n\/\/ ...\nthis.shadowRoot.innerHTML = <code><style>\n    .editable-container {\n      display: flex;\n      align-items: center;\n      gap: 8px;\n    }\n    .display-mode, .edit-mode input {\n      font-size: 1em;\n      padding: 4px 8px;\n    }\n    .save-button, .cancel-button {\n      padding: 6px 12px;\n    }\n\n    \/* Mobil cihazlar i\u00e7in \u00f6zel stiller *\/\n    @media (max-width: 600px) {\n      .editable-container {\n        flex-direction: column; \/* Mobil&#039;de alt alta s\u0131rala *\/\n        align-items: flex-start;\n      }\n      .display-mode, .edit-mode input {\n        font-size: 1.1em; \/* Daha b\u00fcy\u00fck font *\/\n        padding: 8px 12px;\n        width: 100%; \/* Tam geni\u015flik *\/\n        box-sizing: border-box; \/* Padding&#039;i geni\u015fli\u011fe dahil et *\/\n      }\n      .edit-mode {\n        display: flex;\n        flex-direction: column;\n        gap: 8px;\n        width: 100%;\n      }\n      .save-button, .cancel-button {\n        width: 100%; \/* Mobil&#039;de butonlar tam geni\u015flikte olsun *\/\n        padding: 10px 15px;\n      }\n    }\n  <\/style>\n  <div class=\"editable-container\">\n    ${this.isEditing ? this.renderEditMode() : this.renderDisplayMode()}\n    ${this.isLoading ?<\/code><div class=\"loading-spinner\"><\/div><code>: &#039;&#039;}\n  <\/div><\/code>;\n\/\/ ...\n    <\/pre>\n<p><\/code><\/p>\n<p>Yukar\u0131daki \u00f6rnekte, <code>@media (max-width: 600px)<\/code> kural\u0131 ile ekran geni\u015fli\u011fi 600 pikselden az oldu\u011funda elementin g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc de\u011fi\u015ftirdik. <code>.editable-container<\/code> art\u0131k dikey olarak s\u0131ralan\u0131yor, metin ve input alanlar\u0131n\u0131n font boyutlar\u0131 b\u00fcy\u00fcyor ve butonlar tam geni\u015flikte g\u00f6r\u00fcn\u00fcyor. Bu, k\u00fc\u00e7\u00fck ekranlarda daha iyi bir okunabilirlik ve t\u0131klanabilirlik sa\u011flar. Her \u00f6zel element kendi i\u00e7inde bu t\u00fcr responsive kurallar\u0131 bar\u0131nd\u0131rabilir, bu da elementlerinizi kaps\u00fcllenmi\u015f ve ta\u015f\u0131nabilir hale getirirken ayn\u0131 zamanda farkl\u0131 ekran boyutlar\u0131na uyum sa\u011flayabilmesini garanti eder.<\/p>\n<p>Ayr\u0131ca, JavaScript taraf\u0131nda da medya sorgular\u0131n\u0131 kullanmak m\u00fcmk\u00fcnd\u00fcr. <code>window.matchMedia()<\/code> API'si sayesinde, JavaScript i\u00e7inde belirli bir medya sorgusunun durumunu kontrol edebilir ve elementin davran\u0131\u015f\u0131n\u0131 buna g\u00f6re de\u011fi\u015ftirebilirsiniz. \u00d6rne\u011fin, mobil cihazlardaysan\u0131z bir tooltip g\u00f6stermek yerine bir pop-up a\u00e7abilirsiniz. Bu t\u00fcr dinamik davran\u0131\u015f de\u011fi\u015fiklikleri, kullan\u0131c\u0131 deneyimini daha da zenginle\u015ftirir ve farkl\u0131 cihazlarda en uygun etkile\u015fimi sunman\u0131z\u0131 sa\u011flar.<\/p>\n<pre><code>\n\/\/ JavaScript i\u00e7inde medya sorgusu kontrol\u00fc\nif (window.matchMedia('(max-width: 600px)').matches) {\n  \/\/ Mobil cihazlar i\u00e7in \u00f6zel JS davran\u0131\u015flar\u0131\n  console.log(\"Mobil g\u00f6r\u00fcn\u00fcmdeyiz, buton boyutlar\u0131n\u0131 b\u00fcy\u00fctelim!\");\n} else {\n  \/\/ Masa\u00fcst\u00fc i\u00e7in JS davran\u0131\u015flar\u0131\n}\n\n\/\/ Ayr\u0131ca bir dinleyici ekleyerek boyut de\u011fi\u015fti\u011finde tetiklenebilir:\nconst mediaQuery = window.matchMedia('(max-width: 600px)');\nmediaQuery.addEventListener('change', (e) => {\n  if (e.matches) {\n    console.log('Ekran mobil boyuta ge\u00e7ti!');\n    \/\/ Elementin baz\u0131 \u00f6zelliklerini de\u011fi\u015ftir\n  } else {\n    console.log('Ekran masa\u00fcst\u00fc boyuta ge\u00e7ti!');\n    \/\/ Elementin \u00f6zelliklerini geri al\n  }\n});\n    <\/pre>\n<p><\/code><\/p>\n<p>Bu yetenekler, \u00f6zel elementlerinizi yaln\u0131zca g\u00f6rsel olarak de\u011fil, ayn\u0131 zamanda i\u015flevsel olarak da mobil uyumlu hale getirmenizi sa\u011flar. Kaps\u00fcllenmi\u015f olmalar\u0131, responsive stillerinizin veya davran\u0131\u015flar\u0131n\u0131z\u0131n elementin d\u0131\u015f\u0131ndaki di\u011fer bile\u015fenleri etkilemesini engeller, bu da mod\u00fcler ve g\u00fcvenilir bir tasar\u0131m yakla\u015f\u0131m\u0131 sunar.<\/p>\n<h2>Kar\u015f\u0131la\u015f\u0131labilecek Zorluklar ve \u00c7\u00f6z\u00fcm \u00d6nerileri<\/h2>\n<p>Rails uygulamalar\u0131nda \u00f6zel elementlerle sat\u0131r i\u00e7i d\u00fczenleme gibi modern frontend tekniklerini kullan\u0131rken baz\u0131 zorluklarla kar\u015f\u0131la\u015fmak ka\u00e7\u0131n\u0131lmazd\u0131r. Ancak, bu zorluklar\u0131n \u00e7o\u011fu i\u00e7in etkili \u00e7\u00f6z\u00fcmler mevcuttur. \u00d6nemli olan, potansiyel sorunlar\u0131 \u00f6nceden tan\u0131mak ve uygun stratejiler geli\u015ftirmektir.<\/p>\n<p><strong>1. Shadow DOM ve Stillerin Y\u00f6netimi:<\/strong> Shadow DOM, stilleri kaps\u00fclleme konusunda harika bir i\u015f \u00e7\u0131kar\u0131r, ancak bazen bu izolasyon, d\u0131\u015far\u0131dan stil vermek istedi\u011finizde bir zorluk haline gelebilir. \u00d6rne\u011fin, Tailwind CSS gibi bir utility-first framework kullan\u0131yorsan\u0131z, Shadow DOM i\u00e7ine otomatik olarak dahil olmaz.<\/p>\n<ul>\n<li><strong>\u00c7\u00f6z\u00fcm:<\/strong> \u00d6zel elementinizin i\u00e7inde kendi stil etiketlerinizi (<code><br \/>\n<style><\/code>) kullanarak stilleri do\u011frudan Shadow DOM'a enjekte edebilirsiniz. Yukar\u0131daki \u00f6rneklerde g\u00f6rd\u00fc\u011f\u00fcn\u00fcz gibi, bu genellikle en basit yoldur. Daha geli\u015fmi\u015f kontrol i\u00e7in CSS Custom Properties (CSS De\u011fi\u015fkenleri) kullanabilirsiniz. Shadow DOM i\u00e7inde <code>var(--ana-renk, blue)<\/code> gibi de\u011fi\u015fkenler tan\u0131mlayarak, d\u0131\u015far\u0131dan bu de\u011fi\u015fkenlerin de\u011ferlerini ayarlayabilirsiniz. Ayr\u0131ca, baz\u0131 durumlarda (\u00e7ok karma\u015f\u0131k stiller veya entegrasyonlar i\u00e7in) <code>mode: 'closed'<\/code> yerine <code>mode: 'open'<\/code> kullanarak Shadow DOM'u d\u0131\u015far\u0131dan daha eri\u015filebilir hale getirebilir, ancak bu kaps\u00fcllemeyi zay\u0131flat\u0131r.<\/li>\n<\/ul>\n<p><strong>2. Taray\u0131c\u0131 Uyumlulu\u011fu:<\/strong> Web Components standartlar\u0131 modern taray\u0131c\u0131lar taraf\u0131ndan iyi desteklense de, eski taray\u0131c\u0131larda (\u00f6zellikle Internet Explorer) tam destek bulunmayabilir.<\/p>\n<ul>\n<li><strong>\u00c7\u00f6z\u00fcm:<\/strong> Taray\u0131c\u0131 uyumlulu\u011fu i\u00e7in \"polyfills\" kullanabilirsiniz. Web Components i\u00e7in pop\u00fcler bir polyfill k\u00fct\u00fcphanesi <code>webcomponents\/polyfills<\/code>'dir. Bu polyfill'leri projenize dahil ederek, \u00f6zel elementlerinizin daha geni\u015f bir taray\u0131c\u0131 yelpazesinde \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flayabilirsiniz. Ancak, g\u00fcn\u00fcm\u00fczde \u00e7o\u011fu proje i\u00e7in modern taray\u0131c\u0131lara odaklanmak ve eski taray\u0131c\u0131 deste\u011fini kademeli olarak b\u0131rakmak daha yayg\u0131n bir yakla\u015f\u0131md\u0131r.<\/li>\n<\/ul>\n<p><strong>3. CSRF Korumas\u0131 ve AJAX \u0130stekleri:<\/strong> Rails, CSRF sald\u0131r\u0131lar\u0131na kar\u015f\u0131 koruma sa\u011flamak i\u00e7in her formda veya AJAX iste\u011finde bir CSRF token'\u0131 bekler. \u00d6zel elementlerinizden g\u00f6nderilen AJAX isteklerinde bu token'\u0131 manuel olarak eklemeniz gerekir.<\/p>\n<ul>\n<li><strong>\u00c7\u00f6z\u00fcm:<\/strong> Makalemizde g\u00f6sterildi\u011fi gibi, <code>document.querySelector('meta[name=\"csrf-token\"]').getAttribute('content')<\/code> kullanarak token'\u0131 al\u0131p AJAX iste\u011finizin <code>headers<\/code> k\u0131sm\u0131na <code>'X-CSRF-Token'<\/code> olarak eklemelisiniz. Bu, Rails'in g\u00fcvenlik mekanizmalar\u0131n\u0131 do\u011fru bir \u015fekilde kullanman\u0131z\u0131 sa\u011flar.<\/li>\n<\/ul>\n<p><strong>4. Karma\u015f\u0131k Durum Y\u00f6netimi:<\/strong> Basit sat\u0131r i\u00e7i d\u00fczenleme elemanlar\u0131 i\u00e7in JavaScript i\u00e7inde durum (<code>isEditing<\/code>, <code>isLoading<\/code> vb.) y\u00f6netimi yeterli olsa da, elementleriniz daha karma\u015f\u0131k hale geldik\u00e7e bu durum y\u00f6netimi zorla\u015fabilir.<\/p>\n<ul>\n<li><strong>\u00c7\u00f6z\u00fcm:<\/strong> Daha karma\u015f\u0131k durumlar i\u00e7in, \u00f6zel elementlerinizi hafif bir durum y\u00f6netim k\u00fct\u00fcphanesi (\u00f6rne\u011fin, Redux benzeri k\u00fc\u00e7\u00fck bir yap\u0131 veya bir Observables k\u00fct\u00fcphanesi) ile birle\u015ftirmeyi d\u00fc\u015f\u00fcnebilirsiniz. Ya da daha basit bir yakla\u015f\u0131mla, StimulusJS gibi bir k\u00fct\u00fcphaneyi \u00f6zel elementlerinizle birlikte kullanarak, elementlerin d\u0131\u015f\u0131ndaki mant\u0131\u011f\u0131 Stimulus controller'lar\u0131na devredebilirsiniz. Bu, \u00f6zel elementlerinizi sadece UI bile\u015fenleri olarak tutarken, i\u015f mant\u0131\u011f\u0131n\u0131 ayr\u0131 bir katmanda y\u00f6netmenizi sa\u011flar.<\/li>\n<\/ul>\n<p><strong>5. Geli\u015ftirici Deneyimi ve Ara\u00e7lar:<\/strong> \u00d6zel elementler i\u00e7in \u00f6zel bir JSX benzeri sentaks veya geli\u015fmi\u015f geli\u015ftirme ara\u00e7lar\u0131 bulunmad\u0131\u011f\u0131ndan, HTML string'leri ile \u00e7al\u0131\u015fmak bazen daha zahmetli olabilir.<\/p>\n<ul>\n<li><strong>\u00c7\u00f6z\u00fcm:<\/strong> HTML string'leri olu\u015ftururken template literal'lar\u0131 ve dikkatli kod yap\u0131s\u0131 kullanmak, okunabilirli\u011fi art\u0131r\u0131r. Geli\u015fmi\u015f durumlarda, Lit (eski ad\u0131yla LitElement) gibi k\u00fct\u00fcphaneler, \u00f6zel element geli\u015ftirmeyi daha keyifli hale getiren \u015fablonlama motorlar\u0131 ve reaktif veri ba\u011flama \u00f6zellikleri sunar. Lit, Web Components \u00fczerine in\u015fa edilmi\u015f hafif bir k\u00fct\u00fcphanedir ve geli\u015ftirme s\u00fcrecini \u00f6nemli \u00f6l\u00e7\u00fcde h\u0131zland\u0131rabilir.<\/li>\n<\/ul>\n<p>Bu zorluklar\u0131n \u00fcstesinden gelmek, \u00f6zel elementleri Rails uygulamalar\u0131n\u0131za ba\u015far\u0131yla entegre etmenin ve projelerinizde uzun vadede s\u00fcrd\u00fcr\u00fclebilir bir \u00e7\u00f6z\u00fcm elde etmenin anahtar\u0131d\u0131r. Do\u011fru ara\u00e7lar\u0131 ve teknikleri kullanarak, kullan\u0131c\u0131lar\u0131n\u0131za modern ve ak\u0131c\u0131 deneyimler sunmaya devam edebilirsiniz.<\/p>\n<h2>Sonu\u00e7: Rails ve \u00d6zel Elementlerle Gelece\u011fin Kullan\u0131c\u0131 Deneyimi<\/h2>\n<p>Rails, geleneksel sunucu tarafl\u0131 render g\u00fcc\u00fcn\u00fc, h\u0131zl\u0131 geli\u015ftirme yeteneklerini ve sa\u011flam bir backend altyap\u0131s\u0131n\u0131 bir araya getiren bir framework olmaya devam ediyor. Ancak, modern web uygulamalar\u0131n\u0131n de\u011fi\u015fen kullan\u0131c\u0131 beklentileri, frontend taraf\u0131nda da yenilik\u00e7i yakla\u015f\u0131mlar\u0131 zorunlu k\u0131l\u0131yor. \u0130\u015fte bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails geli\u015ftiricilerine, karma\u015f\u0131k frontend framework'lerine tamamen ba\u011fl\u0131 kalmadan, SPA benzeri, ak\u0131c\u0131 ve etkile\u015fimli kullan\u0131c\u0131 deneyimleri olu\u015fturma g\u00fcc\u00fc veriyor.<\/p>\n<p>Bu makalede, sat\u0131r i\u00e7i d\u00fczenlemenin neden g\u00fcn\u00fcm\u00fcz uygulamalar\u0131nda bir zorunluluk haline geldi\u011fini, \u00f6zel elementlerin temelini nas\u0131l ataca\u011f\u0131m\u0131z\u0131, bir Rails backend'i ile nas\u0131l entegre edece\u011fimizi ve ileri d\u00fczey kullan\u0131m senaryolar\u0131 ile performans iyile\u015ftirmelerini detayl\u0131ca inceledik. Shadow DOM'un kaps\u00fclleme yetenekleri, CSS Custom Properties ile stil esnekli\u011fi, debounce ile performans optimizasyonu ve eri\u015filebilirlik (A11y) konular\u0131, \u00f6zel elementlerin sadece bir teknik olmaktan \u00f6te, tam te\u015fekk\u00fcll\u00fc bir \u00e7\u00f6z\u00fcm haline geldi\u011fini g\u00f6steriyor. Ayr\u0131ca, mobil uyumlulu\u011fu sa\u011flamak i\u00e7in medya sorgular\u0131n\u0131n nas\u0131l kullan\u0131labilece\u011fini ve kar\u015f\u0131la\u015fabilece\u011finiz yayg\u0131n zorluklar i\u00e7in \u00e7\u00f6z\u00fcm \u00f6nerilerini de ele ald\u0131k.<\/p>\n<p>Rails ve \u00f6zel elementlerin birle\u015fimi, hem backend'in g\u00fcc\u00fcnden \u00f6d\u00fcn vermeden hem de frontend'de modern bir dokunu\u015f sa\u011flamak isteyen geli\u015ftiriciler i\u00e7in ideal bir yol sunuyor. Bu yakla\u015f\u0131m, mikro-frontend mimarilerine do\u011fru at\u0131lan bir ad\u0131m olarak da g\u00f6r\u00fclebilir, zira her \u00f6zel element ba\u011f\u0131ms\u0131z, yeniden kullan\u0131labilir ve kendi kendine yeten bir birim olarak i\u015flev g\u00f6r\u00fcr. Bu, b\u00fcy\u00fck ve karma\u015f\u0131k uygulamalar\u0131n geli\u015ftirilmesini ve bak\u0131m\u0131n\u0131 kolayla\u015ft\u0131r\u0131r.<\/p>\n<p>Gelecekte, \u00f6zel elementlerin taray\u0131c\u0131 deste\u011fi ve ekosistemi daha da geli\u015fecektir. Lit gibi k\u00fct\u00fcphaneler, geli\u015ftirme s\u00fcrecini daha da optimize ederek bu teknolojinin benimsenmesini h\u0131zland\u0131racakt\u0131r. Rails toplulu\u011fu da Hotwire gibi yeniliklerle, sunucu tarafl\u0131 render ile modern frontend deneyimlerini birle\u015ftirme konusunda liderli\u011fini s\u00fcrd\u00fcrmektedir. \u00d6zel elementleri Rails projelerinize entegre etmek, uygulaman\u0131z\u0131n gelece\u011fe haz\u0131r olmas\u0131n\u0131 sa\u011flarken, kullan\u0131c\u0131lar\u0131n\u0131za bug\u00fcnden daha iyi bir deneyim sunman\u0131z i\u00e7in g\u00fc\u00e7l\u00fc bir ara\u00e7t\u0131r. Bu teknolojiyi benimseyerek, uygulaman\u0131z\u0131n rekabet avantaj\u0131n\u0131 art\u0131rabilir ve geli\u015ftirme s\u00fcrecinizi daha verimli hale getirebilirsiniz.<\/p>\n<h3>S\u0131k\u00e7a Sorulan Sorular (SSS)<\/h3>\n<dl>\n<dt><strong>1. \u00d6zel Elementler (Custom Elements) nedir ve neden kullanmal\u0131y\u0131m?<\/strong><\/dt>\n<dd>\n<p>\u00d6zel Elementler, Web Components standartlar\u0131n\u0131n bir par\u00e7as\u0131d\u0131r ve kendi HTML etiketlerinizi tan\u0131mlaman\u0131za olanak tan\u0131r (\u00f6rne\u011fin, <code><my-button><\/code> veya <code><editable-field><\/code>). Kendi JavaScript mant\u0131\u011f\u0131n\u0131, CSS stillerini ve HTML yap\u0131s\u0131n\u0131 kaps\u00fclleyebilirler, bu da onlar\u0131 yeniden kullan\u0131labilir, mod\u00fcler ve y\u00f6netilebilir UI bile\u015fenleri haline getirir. Rails gibi sunucu tarafl\u0131 render (SSR) yapan uygulamalarda, bu elementler frontend'e SPA benzeri dinamizm katmak i\u00e7in m\u00fckemmel bir yoldur, \u00e7\u00fcnk\u00fc ek bir karma\u015f\u0131k JavaScript framework'\u00fcne ihtiya\u00e7 duymazlar ve taray\u0131c\u0131 standartlar\u0131 \u00fczerinde \u00e7al\u0131\u015f\u0131rlar.<\/p>\n<\/dd>\n<dt><strong>2. Shadow DOM kullanmak zorunlu mu? Avantajlar\u0131 nelerdir?<\/strong><\/dt>\n<dd>\n<p>Hay\u0131r, Shadow DOM kullanmak zorunlu de\u011fildir, \u00f6zel elementinizi do\u011frudan belge DOM'una ekleyebilirsiniz. Ancak Shadow DOM kullanman\u0131n \u00f6nemli avantajlar\u0131 vard\u0131r:<\/p>\n<ul>\n<li><strong>Stil Kaps\u00fcllemesi:<\/strong> Shadow DOM i\u00e7ine yazd\u0131\u011f\u0131n\u0131z CSS, elementin d\u0131\u015f\u0131ndaki stillerden etkilenmez ve d\u0131\u015far\u0131daki stilleri etkilemez. Bu, k\u00fcresel stil \u00e7ak\u0131\u015fmalar\u0131n\u0131 \u00f6nler.<\/li>\n<li><strong>\u0130\u015faretleme Kaps\u00fcllemesi:<\/strong> Elementin HTML yap\u0131s\u0131, d\u0131\u015far\u0131daki JavaScript veya CSS taraf\u0131ndan kolayca de\u011fi\u015ftirilemez. Bu, bile\u015fenin tutarl\u0131l\u0131\u011f\u0131n\u0131 korur.<\/li>\n<\/ul>\n<p>            Bu kaps\u00fclleme, elementlerinizin daha ba\u011f\u0131ms\u0131z ve g\u00fcvenilir olmas\u0131n\u0131 sa\u011flar, bu da b\u00fcy\u00fck projelerde veya farkl\u0131 ekipler taraf\u0131ndan geli\u015ftirilen bile\u015fenlerde b\u00fcy\u00fck bir avantajd\u0131r.<\/p>\n<\/dd>\n<dt><strong>3. \u00d6zel elementlerim Rails'in Hotwire (Turbo, Stimulus) ile uyumlu mu?<\/strong><\/dt>\n<dd>\n<p>Kesinlikle evet! \u00d6zel elementler, taray\u0131c\u0131 standartlar\u0131 \u00fczerine in\u015fa edildi\u011fi i\u00e7in Hotwire ile m\u00fckemmel bir \u015fekilde uyum sa\u011flar. Turbo Frames veya Turbo Streams ile sayfalar\u0131n veya par\u00e7alar\u0131n dinamik olarak g\u00fcncellenmesi durumunda, i\u00e7erikteki \u00f6zel elementler otomatik olarak y\u00fckseltilir ve \u00e7al\u0131\u015f\u0131r. StimulusJS ise, \u00f6zel elementlerinizin d\u0131\u015f\u0131ndaki daha karma\u015f\u0131k sayfa etkile\u015fimlerini y\u00f6netmek veya \u00f6zel elementlerinize d\u0131\u015far\u0131dan veri\/davran\u0131\u015f sa\u011flamak i\u00e7in harika bir tamamlay\u0131c\u0131 olabilir. Her iki teknoloji de birbirini tamamlar ve Rails'te modern, dinamik web uygulamalar\u0131 olu\u015fturmak i\u00e7in g\u00fc\u00e7l\u00fc bir kombinasyon sunar.<\/p>\n<\/dd>\n<dt><strong>4. Sat\u0131r i\u00e7i d\u00fczenleme ile g\u00fcvenlik riskleri var m\u0131? CSRF korumas\u0131 nas\u0131l sa\u011flan\u0131r?<\/strong><\/dt>\n<dd>\n<p>Evet, her AJAX iste\u011finde oldu\u011fu gibi sat\u0131r i\u00e7i d\u00fczenleme de g\u00fcvenlik riskleri bar\u0131nd\u0131r\u0131r, \u00f6zellikle CSRF (Cross-Site Request Forgery) sald\u0131r\u0131lar\u0131na kar\u015f\u0131 dikkatli olunmal\u0131d\u0131r. Rails, varsay\u0131lan olarak bu t\u00fcr sald\u0131r\u0131lara kar\u015f\u0131 koruma sa\u011flar. \u00d6zel elementlerinizden g\u00f6nderilen AJAX isteklerinde bu korumay\u0131 s\u00fcrd\u00fcrmek i\u00e7in, her <code>POST<\/code>, <code>PUT<\/code>, <code>PATCH<\/code> veya <code>DELETE<\/code> iste\u011finde bir CSRF token'\u0131 eklemeniz gerekir. Bu token'\u0131, sayfan\u0131n <code><head><\/code> b\u00f6l\u00fcm\u00fcndeki <code><meta name=\"csrf-token\"><\/code> etiketinden alabilir ve iste\u011finizin <code>X-CSRF-Token<\/code> HTTP ba\u015fl\u0131\u011f\u0131na ekleyebilirsiniz. Makalemizdeki \u00f6rnek kodda bu y\u00f6ntemi g\u00f6stermi\u015ftik.<\/p>\n<\/dd>\n<dt><strong>5. \u00d6zel elementler i\u00e7in hangi geli\u015ftirici ara\u00e7lar\u0131n\u0131 kullanabilirim?<\/strong><\/dt>\n<dd>\n<p>Taray\u0131c\u0131lar\u0131n geli\u015ftirici ara\u00e7lar\u0131, \u00f6zel elementlerle \u00e7al\u0131\u015f\u0131rken en b\u00fcy\u00fck yard\u0131mc\u0131n\u0131zd\u0131r. \u00d6zellikle Chrome'un \"Elements\" panelinde, \u00f6zel elementlerinizi Shadow DOM i\u00e7eri\u011fiyle birlikte g\u00f6rebilirsiniz (Ayarlarda \"Show user agent Shadow DOM\" se\u00e7ene\u011fini aktif etmeniz gerekebilir). Ayr\u0131ca, Lit gibi k\u00fct\u00fcphaneler \u00f6zel element geli\u015ftirmeyi kolayla\u015ft\u0131rmak i\u00e7in kendi ara\u00e7lar\u0131n\u0131 sunar. JavaScript hata ay\u0131klama i\u00e7in taray\u0131c\u0131 konsolu ve debugger'\u0131 standart olarak kullanabilirsiniz. Kodunuzu daha d\u00fczenli tutmak i\u00e7in Prettier ve ESLint gibi linter'lar\u0131 ve bi\u00e7imlendiricileri de projenize dahil etmeniz \u00f6nerilir.<\/p>\n<\/dd>\n<\/dl>\n<p><\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan&hellip;","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1342],"tags":[],"class_list":{"0":"post-34254","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-ai","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Inline D\u00fczenleme: Rails&#039;te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi<\/title>\n<meta name=\"description\" content=\"Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan kald\u0131rarak ak\u0131c\u0131 bir etkile\u015fim sunmak, kullan\u0131c\u0131lar\u0131n uygulaman\u0131zda daha fazla zaman ge\u00e7irmesini sa\u011fl\u0131yor. Peki, Rails gibi geleneksel sunucu tarafl\u0131 render motoruyla bu SPA (Single Page Application) benzeri deneyimi nas\u0131l yakalayabiliriz? \u0130\u015fte tam da bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails uygulamalar\u0131n\u0131za sat\u0131r i\u00e7i d\u00fczenleme (inline editing) g\u00fcc\u00fc kat\u0131yor. Bu makale, Rails backend&#039;ini modern frontend yetenekleriyle birle\u015ftirerek kullan\u0131c\u0131lar\u0131n\u0131za kesintisiz bir deneyim sunman\u0131z i\u00e7in size ad\u0131m ad\u0131m rehberlik edecek.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Inline D\u00fczenleme: Rails&#039;te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi\" \/>\n<meta property=\"og:description\" content=\"Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan kald\u0131rarak ak\u0131c\u0131 bir etkile\u015fim sunmak, kullan\u0131c\u0131lar\u0131n uygulaman\u0131zda daha fazla zaman ge\u00e7irmesini sa\u011fl\u0131yor. Peki, Rails gibi geleneksel sunucu tarafl\u0131 render motoruyla bu SPA (Single Page Application) benzeri deneyimi nas\u0131l yakalayabiliriz? \u0130\u015fte tam da bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails uygulamalar\u0131n\u0131za sat\u0131r i\u00e7i d\u00fczenleme (inline editing) g\u00fcc\u00fc kat\u0131yor. Bu makale, Rails backend&#039;ini modern frontend yetenekleriyle birle\u015ftirerek kullan\u0131c\u0131lar\u0131n\u0131za kesintisiz bir deneyim sunman\u0131z i\u00e7in size ad\u0131m ad\u0131m rehberlik edecek.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-13T21:31:29+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"29 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Inline D\u00fczenleme: Rails&#8217;te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi\",\"datePublished\":\"2025-11-13T21:31:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/\"},\"wordCount\":4518,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"AI\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/\",\"name\":\"Inline D\u00fczenleme: Rails'te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-11-13T21:31:29+00:00\",\"description\":\"Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan kald\u0131rarak ak\u0131c\u0131 bir etkile\u015fim sunmak, kullan\u0131c\u0131lar\u0131n uygulaman\u0131zda daha fazla zaman ge\u00e7irmesini sa\u011fl\u0131yor. Peki, Rails gibi geleneksel sunucu tarafl\u0131 render motoruyla bu SPA (Single Page Application) benzeri deneyimi nas\u0131l yakalayabiliriz? \u0130\u015fte tam da bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails uygulamalar\u0131n\u0131za sat\u0131r i\u00e7i d\u00fczenleme (inline editing) g\u00fcc\u00fc kat\u0131yor. Bu makale, Rails backend'ini modern frontend yetenekleriyle birle\u015ftirerek kullan\u0131c\u0131lar\u0131n\u0131za kesintisiz bir deneyim sunman\u0131z i\u00e7in size ad\u0131m ad\u0131m rehberlik edecek.\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Inline D\u00fczenleme: Rails&#8217;te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Inline D\u00fczenleme: Rails'te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi","description":"Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan kald\u0131rarak ak\u0131c\u0131 bir etkile\u015fim sunmak, kullan\u0131c\u0131lar\u0131n uygulaman\u0131zda daha fazla zaman ge\u00e7irmesini sa\u011fl\u0131yor. Peki, Rails gibi geleneksel sunucu tarafl\u0131 render motoruyla bu SPA (Single Page Application) benzeri deneyimi nas\u0131l yakalayabiliriz? \u0130\u015fte tam da bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails uygulamalar\u0131n\u0131za sat\u0131r i\u00e7i d\u00fczenleme (inline editing) g\u00fcc\u00fc kat\u0131yor. Bu makale, Rails backend'ini modern frontend yetenekleriyle birle\u015ftirerek kullan\u0131c\u0131lar\u0131n\u0131za kesintisiz bir deneyim sunman\u0131z i\u00e7in size ad\u0131m ad\u0131m rehberlik edecek.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/","og_locale":"tr_TR","og_type":"article","og_title":"Inline D\u00fczenleme: Rails'te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi","og_description":"Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan kald\u0131rarak ak\u0131c\u0131 bir etkile\u015fim sunmak, kullan\u0131c\u0131lar\u0131n uygulaman\u0131zda daha fazla zaman ge\u00e7irmesini sa\u011fl\u0131yor. Peki, Rails gibi geleneksel sunucu tarafl\u0131 render motoruyla bu SPA (Single Page Application) benzeri deneyimi nas\u0131l yakalayabiliriz? \u0130\u015fte tam da bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails uygulamalar\u0131n\u0131za sat\u0131r i\u00e7i d\u00fczenleme (inline editing) g\u00fcc\u00fc kat\u0131yor. Bu makale, Rails backend'ini modern frontend yetenekleriyle birle\u015ftirerek kullan\u0131c\u0131lar\u0131n\u0131za kesintisiz bir deneyim sunman\u0131z i\u00e7in size ad\u0131m ad\u0131m rehberlik edecek.","og_url":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-11-13T21:31:29+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"29 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Inline D\u00fczenleme: Rails&#8217;te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi","datePublished":"2025-11-13T21:31:29+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/"},"wordCount":4518,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["AI"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/","url":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/","name":"Inline D\u00fczenleme: Rails'te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-11-13T21:31:29+00:00","description":"Modern web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimi, ba\u015far\u0131n\u0131n anahtarlar\u0131ndan biri haline geldi. Sayfa yenilemelerini en aza indirerek veya tamamen ortadan kald\u0131rarak ak\u0131c\u0131 bir etkile\u015fim sunmak, kullan\u0131c\u0131lar\u0131n uygulaman\u0131zda daha fazla zaman ge\u00e7irmesini sa\u011fl\u0131yor. Peki, Rails gibi geleneksel sunucu tarafl\u0131 render motoruyla bu SPA (Single Page Application) benzeri deneyimi nas\u0131l yakalayabiliriz? \u0130\u015fte tam da bu noktada, \u00f6zel elementler (Custom Elements) devreye girerek Rails uygulamalar\u0131n\u0131za sat\u0131r i\u00e7i d\u00fczenleme (inline editing) g\u00fcc\u00fc kat\u0131yor. Bu makale, Rails backend'ini modern frontend yetenekleriyle birle\u015ftirerek kullan\u0131c\u0131lar\u0131n\u0131za kesintisiz bir deneyim sunman\u0131z i\u00e7in size ad\u0131m ad\u0131m rehberlik edecek.","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/inline-duzenleme-railste-ozel-elementlerle-akici-kullanici-deneyimi\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Inline D\u00fczenleme: Rails&#8217;te \u00d6zel Elementlerle Ak\u0131c\u0131 Kullan\u0131c\u0131 Deneyimi"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34254","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=34254"}],"version-history":[{"count":0,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34254\/revisions"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=34254"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=34254"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=34254"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}