Okay, I'm starting to pull my hair out on this one. I'm new to rails, and was following a tutorial on making a pinterest style app. I finished it but wasn't happy with the up-voting system.
It was refreshing the page every time I clicked to up vote. So I found some post about it and did exactly what it said. It kept loading a page that showed me the js code instead of executing it.
This morning I changed a "put" to "get" then back again, and now it's working... NO IDEA what happened to change it.
BUT, now it's up voting every post on the page instead of just the one I click on. When I hover over the links, they all point to the proper ID for that link.
Here's the code from the controller:
def upvote
#pin.upvote_by current_user
respond_to do |format|
format.html { redirect_to :back }
format.js { render :layout => false }
format.json
end
end
And the view (haml):
.btn-group.pull-right
= link_to like_pin_path(pin), method: :put, remote: true, class: "btn btn-like" do
%span.glyphicon.glyphicon-heart
= pin.get_upvotes.size
Upvote.js.erb:
$('.glyphicon-heart').html('<%=#pin.get_upvotes.size%>');
Routes.rb
Rails.application.routes.draw do
devise_for :users
resources :pins do
member do
put "like", to: "pins#upvote", defaults: { format: 'js' }
end
end
root "pins#index"
end
Here's the log from the console when a like button is clicked:
Started PUT "/pins/10/like" for ::1 at 2015-12-08 11:40:02 -0600
Processing by PinsController#upvote as JS
Parameters: {"id"=>"10"}
Pin Load (0.2ms) SELECT "pins".* FROM "pins" WHERE "pins"."id" = ? LIMIT 1 [["id", 10]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 2]]
(0.3ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."voter_id" = ? AND "votes"."voter_type" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 10], ["votable_type", "Pin"], ["voter_id", 2], ["voter_type", "User"]]
ActsAsVotable::Vote Load (0.6ms) SELECT "votes".* FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."voter_id" = ? AND "votes"."voter_type" = ? AND "votes"."vote_scope" IS NULL ORDER BY "votes"."id" DESC LIMIT 1 [["votable_id", 10], ["votable_type", "Pin"], ["voter_id", 2], ["voter_type", "User"]]
(0.2ms) begin transaction
(0.1ms) commit transaction
(0.2ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL [["votable_id", 10], ["votable_type", "Pin"], ["vote_flag", "t"]]
Rendered pins/upvote.js.erb (4.4ms)
Completed 200 OK in 25ms (Views: 9.4ms | ActiveRecord: 1.8ms)
I'm sure it's something really simple but ajax/js are even newer to me than rails.
Let me know if there's anything else I need to post. Any help will be so greatly appreciated!
Also for future reference, what would make the link load a page with the js code instead of executing the code? Since I don't feel like I changed anything that drastic today, I don't know how I got past that. I'm glad I did, but it would be helpful to know HOW.
It's doing that because your JS is technically targeting all the links with that class. Instead you could append the model's id of the individual pin to the link's class or create a data attribute but it's entirely up to you. In doing so it'll only target the one link that's clicked.
UPDATE:
Essentially you'll want to assign a class (instance's id) to a container div holding the vote button: pin-#{pin.id} for index view and pin-#{#pin.id} for show view.
Controller
def upvote
#pin.upvote_by current_user
respond_to do |format|
format.js { render "upvote.js.erb" }
end
end
Routes
...
resources :pins do
member do
put :upvote
end
end
Index View
...
%div{class: "btn-group pull-right pin-#{pin.id}"}
= render "upvote", pin: pin
Show View
...
.col-md-6
%div{class: "btn-group pull-right pin-#{#pin.id}"}
= render "upvote", pin: #pin
-if user_signed_in?
= link_to "Edit", edit_pin_path, class: "btn btn-default"
= link_to "Delete", pin_path, method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-default"
_upvote.html.haml
= link_to upvote_pin_path(pin), method: :put, remote: :true, class: "btn btn-default btn-like" do
%span.glyphicon.glyphicon-heart
= pin.get_upvotes.size
upvote.js.erb
$(".pin-<%= #pin.id %>").html("<%= escape_javascript(render 'upvote', pin: #pin) %>");
Related
I'm trying to implement a follow/unfollow form to create/destroy a relationship between a user, and a company on a site. I'm having problems rendering a new partial on form submit, to change the relationship button from "follow" to "unfollow"
Currently, I render a different partial depending on whether or not a relationship already exists:
`<% unless current_user.id == #company.user_id %>
<div id="#relationship">
<% if current_user.following?(#company) %>
<%= render :partial => 'unfollow' %>
<% else %>
<%= render :partial => 'follow' %>
<% end %>
</div>
<% end %>`
The follow partial looks like:
<%= form_for(current_user.relationships.build(followed_id: #company.id), remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow",class: "btn-transparent btn-hollow btn-huge" %>
<% end %>
While the unfollow partial looks like:
<%= form_for(current_user.relationships.find_by(followed_id: #company.id), html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn-transparent btn-hollow btn-huge" %>
<% end %>
These use Create and Destroy methods in my Relationships_Controller:
class RelationshipsController < ApplicationController
before_filter :authenticate_user!
def create
#company = Company.find(params[:relationship][:followed_id])
current_user.follow!(#company)
respond_to do |format|
format.html { redirect_to #company }
format.js {render layout: false}
end
end
def destroy
#company = Relationship.find(params[:id]).followed
current_user.unfollow!(#company)
respond_to do |format|
format.html { redirect_to #company }
format.js{render layout: false}
end
end
end
If I set remote: false, the form works as expected, creating and destroying relationships, and the button changes on page reload. When I try to use AJAX by setting remote: true, and use the code below for relationships/create.js.erb and relationships/destroy.js.erb
$("#relationship").html("<%= j render('companies/unfollow') %>");
$("#relationship").html("<%= j render('companies/follow') %>");
However, now when I reload my page - I can click on the button once to create/destroy a relationship object. If I click again, I get a 500 error. The new partial is never loaded.
Although I'm a bit of a noob, this error in seems to point me to this line in the jquery source in chrome dev tools:
xhr.send( ( options.hasContent && options.data ) || null );
I'm using Rails 4, Jquery-Turbolinks and Devise - if any of them bare any relevance to the problem.
Incredibly frustrated now, if anyone could help that would be greatly appreciated!
Update
The log output is below. The first DELETE says that it has rendered my partial, however it has not. The second DELETE is what is happening on clicking unfollow a second time - it rightly points out that the Relationship with that id number no longer exists, as it was deleted on the first action.
Started DELETE "/relationships/429" for 127.0.0.1 at 2014-10-28 14:34:59 +0000
Processing by RelationshipsController#destroy as JS
Parameters: {"utf8"=>"✓", "commit"=>"Unfollow", "id"=>"429"}
[1m[36mUser Load (1.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1[0m
[1m[35mRelationship Load (0.4ms)[0m SELECT "relationships".* FROM "relationships" WHERE "relationships"."id" = $1 LIMIT 1 [["id", 429]]
[1m[36mCompany Load (0.3ms)[0m [1mSELECT "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT 1[0m [["id", 1]]
[1m[35mRelationship Load (0.3ms)[0m SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = $1 AND "relationships"."followed_id" = 1 LIMIT 1 [["follower_id", 1]]
[1m[36m (0.2ms)[0m [1mBEGIN[0m
[1m[35mSQL (3.6ms)[0m DELETE FROM "relationships" WHERE "relationships"."id" = $1 [["id", 429]]
[1m[36m (0.5ms)[0m [1mCOMMIT[0m
Rendered companies/_follow.html.erb (2.5ms)
Rendered relationships/destroy.js.erb (5.3ms)
Completed 200 OK in 19ms (Views: 7.0ms | ActiveRecord: 6.3ms)
Started DELETE "/relationships/429" for 127.0.0.1 at 2014-10-28 14:35:04 +0000
Processing by RelationshipsController#destroy as JS
Parameters: {"utf8"=>"✓", "commit"=>"Unfollow", "id"=>"429"}
[1m[35mUser Load (0.9ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
[1m[36mRelationship Load (0.3ms)[0m [1mSELECT "relationships".* FROM "relationships" WHERE "relationships"."id" = $1 LIMIT 1[0m [["id", 429]]
Completed 404 Not Found in 4ms
ActiveRecord::RecordNotFound - Couldn't find Relationship with 'id'=429:
You have a hash in the name of your ID.
Try changing
<div id="#relationship">
to
<div id="relationship">
When use remote: true you must change:
format.js{render layout: false}
with
format.js
Otherwise: you never render relationships/create.js.erb and relationships/destroy.js.erb
Very new Rails 4 developer here. I've got a form where a user is creating Exercises. Exercises can have many Equipment, and Equipment can be optional( think push-up stands for doing push-ups ). I store this "optional" field on the join table exercise_equipment.
I cannot get the parameters to actually send through the values of the collection element that I pick. See below for the model, view, controller, and parameters.
Here are the attributes/relationships of my models:
# id :integer
# name :string
# is_public :boolean
Exercise
has_many :exercise_equipment
has_many :equipment, :through => :exercise_equipment
accepts_nested_attributes_for :exercise_equipment
# id :integer
# exercise_id :integer
# equipment_id :integer
# optional :boolean
ExerciseEquipment
belongs_to :exercise
belongs_to :equipment
accepts_nested_attributes_for :equipment
# id :integer
# name :string
Equipment
has_many :exercise_equipment
has_many :exercises, :through => :exercise_equipment
Here are some (maybe) relevant controller methods:
def new
#exercise = Exercise.new
#exercise.exercise_equipment.build
end
def create
#exercise = Exercise.new( exercise_params )
if #exercise.save
redirect_to #exercises
else
render 'new'
end
end
def edit
#exercise = Exercise.find( params[:id] )
end
def update
#exercise = Exercise.find( params[:id] )
if #exercise.update_attributes( exercise_params )
redirect_to #exercises
else
render 'edit'
end
end
def exercise_params
params.require( :exercise ).permit(
:name,
:is_public,
exercise_equipment_attributes: [
:id,
:optional,
equipment_attributes: [
:id,
:name
],
]
)
end
This is my shot at creating a view to do what I want:
exercises/new.html.erb
<%= form_for #exercise do |f| %>
<%= render 'form', f: f %>
<%= f.submit "New Exercise" %>
<% end %>
exercises/_form.html.erb
<%= f.label :name %><br />
<%= f.text_field :name %>
<%= f.check_box :is_public %> Public
<%= f.fields_for( :exercise_equipment ) do |eef|
<%= eef.fields_for( :equipment ) do |ef|
ef.collection_select :id, Equipment.all, :id, :name %>
<% end %>
<%= eef.check_box :is_optional %> Optional
<% end %>
When I put all of this together and submit an update to an already-existing exercise, the values all go through the params hash, but aren't changed to the new values I've selected...
Parameters: {
"utf8"=>"[checkbox]",
"authenticity_token"=>"[token]",
"exercise"=>{
"name"=>"Test",
"is_public"=>"1",
"exercise_equipment_attributes"=>{
"0"=>{
"equipment_attributes"=>{
"id"=>"1"
},
"optional"=>"1",
"id"=>"2"
}
}
},
"commit"=>"Save Exercise",
"id"=>"1"
}
If you can help me out, I'd be super appreciative. Just let me know if you need any more information and I can provide it.
EDIT
Here is the state of the database before updating:
postgres#=>db=# select id, name, is_public from exercises;
id | name | is_public
----+------+-----------
2 | Test | t
(1 row)
Time: 61.279 ms
postgres#=>db=# select id, exercise_id, equipment_id, optional from exercise_equipment;
id | exercise_id | equipment_id | optional
----+-------------+--------------+----------
2 | 2 | 1 | t
(1 row)
Time: 58.819 ms
postgres#=>db=# select id, name from equipment where id = 1;
id | name
----+-------------
1 | Freeweights
(1 row)
I then go to the update route for that exercise, select a different equipment from the collection, and submit the form. I get the following Rails Console results:
Started PATCH "/exercises/system-test" for 127.0.0.1 at 2014-08-12 23:48:18 -0400
Processing by ExercisesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PsbbUPSCiIew2Fd22Swn+K4PmLjwNDCrDdwXf9YBcm8=", "exercise"=>{"name"=>"Test", "is_public"=>"1", "exercise_equipment_attributes"=>{"0"=>{"equipment_attributes"=>{"id"=>"1"}, "optional"=>"1", "id"=>"2"}}}, "commit"=>"Save Exercise", "id"=>"system-test"}
Exercise Load (60.5ms) SELECT "exercises".* FROM "exercises" WHERE "exercises"."slug" = 'system-test' ORDER BY "exercises"."id" ASC LIMIT 1
(57.3ms) BEGIN
ExerciseEquipment Load (76.2ms) SELECT "exercise_equipment".* FROM "exercise_equipment" WHERE "exercise_equipment"."exercise_id" = $1 AND "exercise_equipment"."id" IN (2) [["exercise_id", 2]]
Equipment Load (59.1ms) SELECT "equipment".* FROM "equipment" WHERE "equipment"."id" = $1 LIMIT 1 [["id", 1]]
User Load (60.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 10]]
Exercise Exists (60.5ms) SELECT 1 AS one FROM "exercises" WHERE ("exercises"."name" = 'Test' AND "exercises"."id" != 2 AND "exercises"."user_id" = 10) LIMIT 1
(64.8ms) COMMIT
Redirected to http://localhost:3000/exercises/system-test
Completed 302 Found in 590ms (ActiveRecord: 580.0ms)
Started GET "/exercises/system-test" for 127.0.0.1 at 2014-08-12 23:48:19 -0400
Processing by ExercisesController#show as HTML
Parameters: {"id"=>"system-test"}
Exercise Load (64.1ms) SELECT "exercises".* FROM "exercises" WHERE "exercises"."slug" = 'system-test' ORDER BY "exercises"."id" ASC LIMIT 1
Equipment Load (58.7ms) SELECT "equipment".* FROM "equipment" INNER JOIN "exercise_equipment" ON "equipment"."id" = "exercise_equipment"."equipment_id" WHERE "exercise_equipment"."exercise_id" = $1 [["exercise_id", 2]]
Rendered exercises/show.html.erb within layouts/application (122.7ms)
User Load (60.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 10 ORDER BY "users"."id" ASC LIMIT 1
Rendered shared/_header.html.erb (61.9ms)
Rendered shared/_alerts.html.erb (0.1ms)
Completed 200 OK in 264ms (Views: 21.3ms | ActiveRecord: 240.8ms)
Firstly, you need to make sure you define your associations correctly.
Any has_many association should be defined with a plural name -
#app/models/exercise.rb
Class Exercise < ActiveRecord::Base
has_many :exercise_equipments
has_many :equipments, :through => :exercise_equipments
accepts_nested_attributes_for :exercise_equipments
end
#app/models/exercise_equipment.rb
Class ExerciseEquipment < ActiveRecord::Base
belongs_to :exercise
belongs_to :equipment
end
#app/models/equipment.rb
Class Equipment < ActiveRecord::Base
has_many :exercise_equipments
has_many :exercises, through: :exercise_equipments
end
If you've already got it working, and are happy with what you've got, then I'd recommend keeping your current setup. However, you may wish to adopt the above for convention's sake
Edit I see from the deleted answer that Beartech investigated this, and turns out Rails treats Equipment / Equipments as the same. Will be worth ignoring the above, but I'll leave it for future reference
Params
I cannot get the parameters to actually send through the values of the
collection element that I pick. See below for the model, view,
controller, and parameters.
I think I get what you mean - you're looking to update the record, but it does not send through the updated parameters to your controller, hence preventing it from being updated.
Although I can't see any glaring problems, I would recommend the issue is that you're trying to populate the exercise_id of an Exercise object. You need to define it for the exercise_equipment object:
<%= f.fields_for :exercise_equipment do |eef| %>
<%= eef.collection_select :equipment_id, Equipment.all, :id, :name %>
<%= eef.check_box :is_optional %>
<% end %>
This will populate your exercise_equipment table as described here:
Time: 61.279 ms
postgres#=>db=# select id, exercise_id, equipment_id, optional from exercise_equipment;
id | exercise_id | equipment_id | optional
----+-------------+--------------+----------
2 | 2 | 1 | t
(1 row)
Currently, you're populating the Equipment model with equipment_id - which won't work. Populating the model in that way will server to create a new record, not update the ones already created
Extra Field
I want to have a link to add an additional equipment field when it is
clicked, similar to how Ryan Bates did it in this RailsCast, but the
helper method he writes( see "Show Notes" tab if you're not subscribed
to see the source ) seems to become substantially more complex when
dealing with the nested views shown in my code below. Any help in
dealing with this?
This a trickier mountain to overcome
Ryan uses quite an outdated method in this process (to pre-populate the link and then just let JS append the field). The "right" way is to build a new object & append the fields_for from ajax. Sounds tough? That's because it is :)
Here's how you do it:
#config/routes.rb
resources :exercises do
collection do
get :ajax_update #-> domain.com/exercises/ajax_update
end
end
#app/models/exercise.rb
Class Exercise < ActiveRecord::Base
def self.build
exercise = self.new
exercise.exercise_equipment.build
end
end
#app/controllers/exercises_controller.rb
Class ExercisesController < ApplicationController
def new
#exercise = Exercise.build
end
def ajax_update
#exercise = Exercise.build
render "add_exercise", layout: false #> renders form with fields_for
end
end
#app/views/exercises/add_exercise.html.erb
<%= form_for #exercise do |f| %>
<%= render partial: "fields_for", locals: { form: f } %>
<% end %>
#app/views/exercises/_fields_for.html.erb
<%= f.fields_for :exercise_equipment, child_index: Time.now.to_i do |eef| %>
<%= eef.collection_select :equipment_id, Equipment.all, :id, :name %>
<%= eef.check_box :is_optional %>
<% end %>
#app/views/exercises/edit.html.erb
<%= form_for #exercise do |f| %>
<%= render partial: "fields_for", locals: { form: f } %>
<%= link_to "Add Field", "#", id: "add_field" %>
<% end %>
#app/assets/javascripts/application.js
$(document).on("click", "#add_field", function() {
$.ajax({
url: "exercises/ajax_update",
success: function(data) {
el_to_add = $(data).html()
$('#your_id').append(el_to_add)
}
});
});
I'm trying to build a RoR app, with three models:
Games that can be classified in a Sector(called GameSector) and in a subsector (called GameSubsector)
A sector is made up of many subsectors.
a Subsector.
Here are my basic models relationships:
models/game.rb
belongs_to :game_sector, :foreign_key => 'game_sector_id', :counter_cache => true
belongs_to :game_subsector, :foreign_key => 'game_subsector_id',:counter_cache => true
I use Active Admin to input the Games, Sectors or subsectors information.
I have a very basic form when I create a game and I'd just like to make the second select drop down (game_subsector) adjust on the choice of the first select (gamesector) so that I don't the the whole (very long) list of game_subsectors but only those that belong to the game_sector I choose.
After dozens of tests and techniques tried but failing, I've finally used this dev's advice that appeared relevant to me: http://samuelmullen.com/2011/02/dynamic-dropdowns-with-rails-jquery-and-ajax/.
But it still does not work.
Here is the form on Active Admin which is located on admin/game.rb
ActiveAdmin.register Game do
menu :parent => "Campaigns", :priority => 1
controller do
with_role :admin_user
def game_subsectors_by_game_sector
if params[:id].present?
#game_subsectors = GameSector.find(params[:id]).game_subsectors
else
#game_subsectors = []
end
respond_to do |format|
format.js
end
end
end
form do |f|
f.inputs "Details" do
f.input :name
f.input :game_sector_id,
:label => "Select industry:",
:as => :select, :collection => GameSector.all(:order => :name),
:input_html => { :rel => "/game_sectors/game_subsectors_by_game_sector" }
f.input :game_subsector_id, :as => :select, :collection => GameSubsector.all(:order => :name)
f.actions
end
I feel the javascript is even maybe not fired.
The jquery I use is located on app/assets/javascript/admin/active_admin.js (I changed config so it loads this javascript when loading active admin pages)
jQuery.ajaxSetup({
'beforeSend': function(xhr) { xhr.setRequestHeader("Accept", "text/javascript"); }
});
$.fn.subSelectWithAjax = function() {
var that = this;
this.change(function() {
$.post(that.attr('rel'), {id: that.val()}, null, "script");
});
};
$("#game_game_sector_id").subSelectWithAjax(); //it it found in my view???
Finally I created a view as this expert adviced: in app/views/layout/ game_subsectors_by_game_sector.js.erb
$("#game_game_subsector_id").html('<%= options_for_select(#game_subsectors.map {|sc| [sc.name, sc.id]}).gsub(/n/, '') %>');
I'm not sure I have out it in the right place though...
What you need is:
Inspect with your web browser console your selects, and use a CSS selector to create a jQuery object for the sector select, something like:
$('#sector_select')
Append to this object a handler, so when it changes AJAX request is fired:
$('#sector_select').change(function(){
$.ajax('/subsectors/for_select', {sector_id: $(this).val()})
.done(function(response){ // 3. populate subsector select
$('#subsector_select').html(response);
});
});
See 3 in code, you need to inspect to get the right CSS selector. Be sure you are getting the expected response in the Network tab of your web browser inspector(if using Chrome).
You need a controller that answers in /subsectors/for_select, in the file app/controllers/subsectors_controller.rb:
class SubsectorsController < ApplicationController
def for_select
#subsectors = Subsector.where sector_id: params[:sector_id]
end
end
You need a view that returns the options to be populated app/views/subsectors/for_select.html.erb:
<% #subsectors.each do |ss| %>
<option value="<%= ss.id %>"><%= ss.name %></option>
<% end %>
You need a route:
get '/subsectors/for_select', to: 'subsectors#for_select'
Hello I'm trying to call a function that I wrote on my controller from my javascript as result of an action when I click on a button.
I followed that thread but it's not worked at all. When I click on the button I get the error listed bellow:
Started GET "/projects/:id/repository/:branch" for 127.0.0.1 at 2013-11-29 15:03:43 -0200
Processing by RepositoriesController#show as */*
Parameters: {"id"=>":id", "repository_id"=>":branch"}
←[1m←[35m (0.0ms)←[0m SELECT MAX(`settings`.`updated_on`) AS max_id FROM `settings`
←[1m←[36mUser Load (0.0ms)←[0m ←[1mSELECT `users`.* FROM `users` WHERE `users`.`type` IN ('User', 'AnonymousUser') AND `users`.`status` = 1 AND `users`.`
id` = 10 LIMIT 1←[0m
Current user: guilherme.noronha (id=10)
←[1m←[35mProject Load (1.0ms)←[0m SELECT `projects`.* FROM `projects` WHERE `projects`.`identifier` = ':id' LIMIT 1
Rendered common/error.html.erb (1.0ms)
Filter chain halted as :find_project_repository rendered or redirected
Completed 404 Not Found in 24ms (Views: 21.0ms | ActiveRecord: 1.0ms)
I didn't understand well why I get this error, so I'm here to ask for help.
Bellow my code to try to detect some mistake or absence of something:
_view_button_release.html.erb
<script>
function CallExec(rep) {
$.ajax("/projects/:id/repository/:branch");
}
</script>
<div class="contextual">
<% if User.current.allowed_to?(:exec, #project) %>
<%= button_to_function l(:gerar_build_project), 'CallExec("'+params[:repository_id].to_s+'")' %>
|
<% end %>
</div>
routes.rb
resources :repositories do
match 'projects/:id/repository', :action => 'exec_client', :controller => 'repositories', :via => :post
match 'projects/:id/repository/:branch', :action => 'exec_client', :controller => 'repositories', :via => :post
get :exec_client, on: :collection
end
client.rb (hook)
module InstanceMethods
require_dependency 'repositories_controller'
def exec_client
begin
...
end
end
end
Any suggestion?
UPDATE:
New Log
Started GET "/projects/b1309/repository/b1309i11/" for 127.0.0.1 at 2013-12-02 10:38:00 -0200
Processing by RepositoriesController#show as */*
Parameters: {"id"=>"b1309", "repository_id"=>"b1309i11"}
←[1m←[35m (0.0ms)←[0m SELECT MAX(`settings`.`updated_on`) AS max_id FROM `settings`
←[1m←[36mUser Load (0.0ms)←[0m ←[1mSELECT `users`.* FROM `users` WHERE `users`.`type` IN ('User', 'AnonymousUser') AND `users`.`status` = 1 AND `users`.`
id` = 10 LIMIT 1←[0m
Current user: guilherme.noronha (id=10)
1st. In your js code
$.ajax("/projects/:id/repository/:branch");
you need insert instead of :id project identificator, instead of :branch branch id or branch name (I don't know what controller expects).
2nd. You need to pass params correctly, because I don't see any of them into log. I see params taken from url Parameters: {"id"=>":id", "repository_id"=>":branch"}. How to pass params through ajax you can google. For example you can check jquery doc and find examples.
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"]) %>
Click here for a Random letsgo
<%= 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
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.
Here you have some good read about random rows:
http://jan.kneschke.de/projects/mysql/order-by-rand/
I've never done this but you can probably do
def random
Letsgos.find(Letsgo.pluck(:id).sample)
end