5

I want to provide users a 'random' option so they can select a previous created date idea to use from the database (inside the letsgos table). There’s a “Let’s Go...” section that users can fill out a form and propose a date they would like to go on. There are going to be users who won’t be able to come up with a date idea on their own. So for those users who cannot create their own date I want to provide a ‘random’ button that with each click will insert a date (that’s from the database) into the form. The dates in the database from the letsgos table have content and tag assign to them. When a user clicks on random it should populate the form with the content and tag (each random click should show new data from the database). I don't have any javascript experience so I am not sure if I am doing it the right way.

/views/letsgos/_form.html.erb:

   <%= form_for(@letsgo) do |f| %>
    <div class="field">
        <%= f.text_area :content, placeholder: "Propose new date..." %>
        </div>
        <%= f.select :tag, options_for_select( [["Select One", ""], "Eat/Drink", "Listen/Watch", "Play", "Explore", "Other"]) %>
        <a href="/letsgos/random" class="ajax">Click here for a Random letsgo</a>
        <%= f.submit "Post" %>

        <% end %>

/views/layouts/application.html.erb

<head>
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>

<script>
  $(document).ready(function() {
    $('.ajax').click(function() {
      $.get(this.href, function(response) {
        console.log(response);
        $('body').html(response); 
      });
    });
  });
<script>
</head>

letsgo controller:

  def create
    @letsgo = current_user.letsgos.build(letsgo_params)
    if @letsgo.save
      flash[:success] = "Date posted!"
      redirect_to root_url
else
      flash[:error] = "Date was not posted!"
      redirect_to root_url
end
end
  def destroy
    @letsgo.destroy
    redirect_to root_url
  end

def random
  @letsgo = Letsgo.random.first
  if request.xhr?
  end
end

private

def letsgo_params
  params.require(:letsgo).permit(:content, :tag)
end

def correct_user
  @letsgo = current_user.letsgos.find_by(id: params[:id])
  redirect_to root_url if @letsgo.nil?
end

Caching columns migration:

rails g migration add_ids_count

def self.up
add_column :letsgos, :ids_count, :integer, :default => 0

 Letsgo.reset_column_information
    Letsgo.all.each do |l|
      l.update_attribute :id_count, l.id.length
    end
  end

 def self.down
    remove_column :letsgos, :id_count
  end
end
Cornelius Wilson
  • 2,844
  • 4
  • 21
  • 41
  • whats the actual queston? – Langusten Gustel Oct 21 '13 at 18:52
  • I do not know how to create the code so that for the 'Lets Go' form, a user can click a 'Random' link that will auto generate the form for the user. Each 'Random' click will choose a entry (content & tag) from the 'Letsgos' table. – Cornelius Wilson Oct 21 '13 at 18:59
  • I guess you have a route to edit this lets-go ideas like */letsgo/:id ? – Langusten Gustel Oct 21 '13 at 19:06
  • 4
    A tip on using RANDOM() or RAND(), is that it scans the entire table and then just returns one. This can be really bad for big tables. Check this answer using offset: http://stackoverflow.com/a/5342324/23915 – Unixmonkey Oct 21 '13 at 19:21

3 Answers3

3

A creative solution to this would be to set up a caching column to store an array of IDs of Letsgo's, if you're worried about the performance on Antarr Byrd's suggestion. Basically, this would cache the Letsgo.pluck(:id) in a single column in the DB. (Maybe do this in a worker in a post-save and/or post-delete hook on Letsgos.) I'd recommend doing this in a buffer of some sort, or maybe as an hourly task.

You could then either pull this in as a JavaScript array (letsgos_ids_array in the example) and create a Math.random() value based on the length of that array and send it to the .find(). Of course you could also just output the array's length directly.

var item_index = Math.floor(Math.random() * letsgos_ids_array_length);
$.get("/letsgos/random", {
    "ind" : item_index
}, function(data){
    /* do something with the data */
});

Then, this index can be used to pull out the actual ID value from the array from the db.

letsgoarray = Letsgosarray.first # this is the single-column "cached" array of IDs
item_id = letsgosarray[params[:id_index]]
@random_letsgo = Letsgos.find(item_id)
format.json do {
    render json: @random_letsgo
}

Array access is fast, and so is single db column querying.

1

Here you have some good read about random rows:

http://jan.kneschke.de/projects/mysql/order-by-rand/

0

I've never done this but you can probably do

def random
  Letsgos.find(Letsgo.pluck(:id).sample)
end
Antarr Byrd
  • 24,863
  • 33
  • 100
  • 188