You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rails中通过Ajax获取不重复的随机单条记录?

Fixing Duplicate Random Records in Rails + Ajax

Hey there, let's work through this problem step by step. I've tackled similar requirements before, so here's how you can reliably fetch 10 unique random records one at a time via Ajax in Rails, no duplicates included.

First: Diagnose the Previous Issues

Your initial attempts (using Model.all.sample or offset + first) can cause duplicates because each request runs independently—there's no state tracking between them. When you tried passing an array of displayed IDs to the backend, the issue was likely either:

  • The backend didn't properly exclude those IDs from the query, or
  • The parameter wasn't parsed correctly (e.g., kept as strings instead of integers, leading to invalid SQL).

Solution: Frontend State + Backend Filtering

We'll maintain a list of displayed record IDs on the frontend, then pass that list to the backend with each request to exclude those entries from the random selection.

Step 1: Frontend Code (Track Displayed IDs & Handle Ajax)

Use JavaScript to keep track of which IDs you've already shown, and send that array to Rails with each request. Here's a jQuery example (adjust for vanilla JS or React/Vue if needed):

// Initialize an empty array to store IDs of displayed records
let displayedIds = [];
const MAX_RECORDS = 10;

function fetchUniqueRandomRecord() {
  // Stop if we've already fetched 10 records
  if (displayedIds.length >= MAX_RECORDS) {
    alert("You've viewed all 10 unique random records!");
    return;
  }

  $.ajax({
    url: "/your_controller/random_record", // Update to your actual route
    method: "GET",
    data: { exclude_ids: displayedIds },
    success: function(record) {
      if (!record) {
        alert("No more unique records available in the database!");
        return;
      }

      // Render the record in your UI (customize this to match your view)
      $("#records-container").append(`
        <div class="record-item">
          <h3>${record.title}</h3>
          <p>${record.description}</p>
        </div>
      `);

      // Add the new record's ID to our tracked list
      displayedIds.push(record.id);
    },
    error: function() {
      alert("Oops, something went wrong fetching the record.");
    }
  });
}

// Bind the function to a button click or other trigger
$("#fetch-record-btn").on("click", fetchUniqueRandomRecord);

Step 2: Backend Controller Code (Filter & Fetch Random Record)

In your Rails controller, receive the exclude_ids parameter, sanitize it to prevent SQL injection, and query for a random record that's not in the excluded list.

class YourController < ApplicationController
  def random_record
    # Sanitize the input: convert to integer array to avoid SQL injection risks
    exclude_ids = Array(params[:exclude_ids]).map(&:to_i)

    # Fetch a random record excluding the already displayed IDs
    # Note: Use RAND() for MySQL, RANDOM() for PostgreSQL/SQLite
    record = YourModel.where.not(id: exclude_ids).order("RANDOM()").first

    # Return the record as JSON (or adjust format if needed)
    render json: record
  end
end

Step 3: Add the Route

Don't forget to add the route in config/routes.rb:

get "your_controller/random_record"

Key Notes for Reliability

  • Database Random Function: Adjust the order clause based on your database:
    • PostgreSQL/SQLite: order("RANDOM()")
    • MySQL: order("RAND()")
  • Parameter Sanitization: Always convert exclude_ids to integers—this prevents malicious SQL injection attempts and ensures the query works correctly.
  • Edge Case Handling: The code checks if no records are left (when record is nil) and stops once 10 records are fetched, so users don't get stuck in infinite loops or empty responses.
  • Performance: If your database has thousands of records, where.not(id: exclude_ids) is still efficient enough for this use case. For extremely large datasets, you could pre-generate a list of 10 unique random IDs upfront and serve them one by one, but that's overkill for most apps.

Why This Works

By maintaining state (the displayedIds array) on the frontend and using it to filter backend queries, each request only selects from records that haven't been shown yet. This eliminates duplicates entirely while keeping the "one request at a time" flow you want.

内容的提问来源于stack exchange,提问作者Mido

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:31:28