I have a button click that triggers the following function. It calls the below asynchronous request.
<script>
function buy_now(user_id, deal_id) {
var purchase_confirmed = confirm("Are you sure you want to make this purchase?");
var theUrl = "/orders/create?user_id=" + user_id + "&deal_id=" + deal_id;
if(purchase_confirmed){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, true ); // true for asynchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
}
</script>
orders_controller.rb
class OrdersController < ApplicationController
def create
#order = Order.new(user_id: orders_params[:user_id], deal_id: orders_params[:deal_id])
unless #order.save
url = "/deals/today_deal?user_id=" + orders_params[:user_id]
redirect_to url, status: :unprocessable_entity
end
end
private
def orders_params
params.permit(:user_id, :deal_id)
end
end
create.html.erb
<h1> Order successful </h1>
routes.rb
ails.application.routes.draw do
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
root 'deals#today_deal'
get '/deals', to: 'deals#index'
get '/deals/today', to: 'deals#today_deal'
get '/deals/new', to: 'deals#new'
get '/deals/:id', to: 'deals#show'
post '/deals/create', to: 'deals#create'
get '/orders/create', to: 'orders#create'
#set all incorrect paths to go to the root path
match '*path' => redirect('/'), via: :get
end
The problem is that once the create action(shown above) in the orders_controller is called and the subsequent view(shown above) is rendered the screen is not updated with the new view. I understand that I don't understand some concept here. It would great if you could point me to some resources to understand what I am doing wrong here. Thank you for your time.
Related
I'm new to programming and sorry if this is a stupid question. I'm writing a test for controllers in Ruby on Rails. The test is expecting a parameter but I'm not sure how to do that. When I run the test with rspec I get the error you see in the title.
This is PART of the controller's code:
class DemographicDetailController < ApplicationController
#before_filter :authorize
include ::Demographic
def show
#cinema_id = params[:cinema_id]
#cinema = Cinema.find(#cinema_id)
#cinema_name = #cinema.name
#cinmea_address = #cinema.address.full_street_address
#cinema_authority_id = #cinema.address.post_code.local_authority_id
#c_working_age = Population.where(:local_authority_id => #cinema_authority_id , :year => Population.maximum("year")).first
#c_working_age = #c_working_age.working_age_16_to_64
#c_total_population = totalpopulation(#cinema_authority_id)
#c_average_income = latestaverageincome(#cinema_authority_id)
#all_cinemas = Cinema.all
(...)
end
and this is the test I wrote for show method:
describe "Demographic" do
context "when testing the DemographicDetail controller" do
#let(:params) { { disabled: false } }
let(:cinema_id) { create(:cinema) }
it "should show demoraphic details successfully" do
get :show, params: { id: #cinema_id }
assert_response :success
end
end
This is the route:
controller :demographic_detail do
get '/demographic_detail/show/:cinema_id' => :show
end
Try this
modify the route as
get '/demographic_detail/show' => 'demographic_detail#show'
Try this:
get '/demographic_details/:cinema_id' => 'demographic_detail#show'
or
controller :demographic_detail do
get '/demographic_detail/:cinema_id' => :show
end
I am sort of new to rails and I am trying to upload images directly to S3 with Shrine. I got direct uploads to S3 to work perfectly, however, when I introduced jquery file upload and upload an image, chrome console throws
this error
at me. I'm not sure what I'm doing wrong and I can't seem to find a solution anywhere online. I get that it's a presign error and it's probably not finding the cache link but I don't know how to resolve that.
EDIT: This was solved by including the presign code in the Routes file and altering the storage location in the uploads.js to the correct location. Now, however, I have an issue with the files being rolled back when they attempt to upload.
I'm using the cloud based ide C9,
This is my uploads.js file:
$(document).on("turbolinks:load", function(){
$("[type=file]").fileupload({
add: function(e, data) {
console.log("add", data);
data.progressBar = $('<div class="progress"><div class="determinate"
style="width: 70%"></div></div>').insertBefore("form")
var options = {
extension: data.files[0].name.match(/(\.\w+)?$/)[0], //set the
file extention
_: Date.now() //prevent caching
};
$.getJSON("/autos/upload/cache/presign", options, function(result) {
console.log("presign", result);
data.formData = result['fields'];
data.url = result['url'];
data.paramName = "file";
data.submit()
});
},
progress: function(e, data) {
console.log("progress", data);
var progress = parseInt(data.loaded / data.total * 100, 10);
var percentage = progress.toString() + '%'
data.progressBar.find(".progress-bar").css("width",
percentage).html(percentage);
},
done: function(e, data) {
console.log("done", data);
data.progressBar.remove();
var image = {
id: data.formData.key.match(/cache\/(.+)/)[1], // we have to
remove the prefix part
storage: 'cache',
metadata: {
size: data.files[0].size,
filename: data.files[0].name.match(/[^\/\\]+$/)[0], // IE return full
path
mime_type: data.files[0].type
}
}
form = $(this).closest("form");
form_data = new FormData(form[0]);
form_data.append($(this).attr("name"), JSON.stringify(image))
$.ajax(form.attr("action"), {
contentType: false,
processData: false,
data: form_data,
method: form.attr("method"),
dataType: "json"
}).done(function(data) {
console.log("done from rails", data);
});
}
});
});
My routes.rb file includes:
mount ImageUploader::UploadEndpoint => "/images/upload"
mount Shrine.presign_endpoint(:cache) => "/autos/upload/cache/presign"
I have a model which accepts these images as well as other fields called Autos, this is included in the Autos file:
include ImageUploader[:image]
My Autos Controller is:
class AutosController < ApplicationController
before_action :find_auto, only: [:show, :edit, :update, :destroy]
def index
#autos = Auto.all.order("created_at DESC")
end
def show
end
def new
#auto = current_user.autos.build
end
def create
#auto = current_user.autos.build(auto_params[:auto])
if #auto.save
flash[:notice] = "Successfully created post."
redirect_to autos_path
else
render 'new'
end
end
def edit
end
def update
if #auto.update(auto_params[:auto])
flash[:notice] = "Successfully updated post."
redirect_to auto_path(#auto)
else
render 'edit'
end
end
def destroy
#auto.destroy
redirect_to autos_path
end
private
def auto_params
params.require(:auto).permit(:title, :price, :description, :contact, :image, :remove_image)
end
def find_auto
#auto = Auto.find(params[:id])
end
end
Assuming your image_uploader.rb has the ImageUploader class defined and given that your presign endpoint is something like /autos/upload/cache/presign, your routes.rb should have the presign route defined like so:
mount ImageUploader.presign_endpoint(:cache) => '/autos/upload/cache/presign'
I hope this single change in the route file would make you able to get the presign object that should contain 3 keys: url, fields and headers
# GET /autos/upload/cache/presign
{
"url": "https://my-bucket.s3-eu-west-1.amazonaws.com",
"fields": {
"key": "cache/b7d575850ba61b44c8a9ff889dfdb14d88cdc25f8dd121004c8",
"policy": "eyJleHBpcmF0aW9uIjoiMjAxNS0QwMToxMToyOVoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJzaHJpbmUtdGVzdGluZyJ9LHsia2V5IjoiYjdkNTc1ODUwYmE2MWI0NGU3Y2M4YTliZmY4OGU5ZGZkYjE2NTQ0ZDk4OGNkYzI1ZjhkZDEyMTAwNGM4In0seyJ4LWFtei1jcmVkZW50aWFsIjoiQUtJQUlKRjU1VE1aWlk0NVVUNlEvMjAxNTEwMjQvZXUtd2VzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotYWxnb3JpdGhtIjoiQVdTNC1ITUFDLVNIQTI1NiJ9LHsieC1hbXotZGF0ZSI6IjIwMTUxMDI0VDAwMTEyOVoifV19",
"x-amz-credential": "AKIAIJF55TMZYT6Q/20151024/eu-west-1/s3/aws4_request",
"x-amz-algorithm": "AWS4-HMAC-SHA256",
"x-amz-date": "20151024T001129Z",
"x-amz-signature": "c1eb634f83f96b69bd675f535b3ff15ae184b102fcba51e4db5f4959b4ae26f4"
},
"headers": {}
}
When upload starts, you will now find this object in developer console instead of the previous 404 not found error.
UPDATE
I think you are very close to the solution. In your create/update actions, use auto_params[:auto] instead of auto_params
You would also like to check the RoR guide on Association Basics for collection methods
I think you following the tutorial of gorails direct upload s3
in you gem file make sure you use the right roda version
gem 'roda', "~> 2.29.0"
I'm trying to let Angular JS and Ruby on Rails communicate for sharing some data in an example application.
I generated a resource called Entries, and made this controller:
class EntriesController < ApplicationController
respond_to :json
def index
respond_with Entry.all
end
def show
respond_with Entry.find(params[:id])
end
def create
respond_with Entry.create(params[:entry])
end
def update
respond_with Entry.update(params[:id], params[:entry])
end
def destroy
respond_with Entry.destroy(params[:id])
end
end
This generates a response in json with the Entries data. I seeded the Entries database:
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
Entry.create!(name: "name1")
Entry.create!(name: "name2")
Entry.create!(name: "name3")
Entry.create!(name: "name4")
Entry.create!(name: "name5")
Entry.create!(name: "name6")
Entry.create!(name: "name7")
I created some entries. I need to let Angular receive them. This is my js file:
var rafflerApp = angular.module('rafflerApp', ["ngResource"]);
rafflerApp.controller('RaffleCtrl', function ($scope, $resource) {
//entries list
Entry = $resource("/entries/:id", {id: "#id"}, {update: {method: "PUT"}})
$scope.entries = Entry.query();
//add a name to the list
$scope.addEntry = function(entry){
entry = Entry.save($scope.newEntry);
$scope.entries.push(entry);
$scope.newEntry = {}
}
//draw a winner
$scope.selectWinner = function(draw){
pool = [];
angular.forEach($scope.entries, function(entry){
if (!entry.winner){
pool.push(entry)
}
});
if (pool.length > 0){
entry = pool[Math.floor(Math.random()*pool.length)]
entry.winner = true
entry.$update(entry)
$scope.lastWinner = entry
}
}
});
If I try the application, I don't receive any js errors, but the list is empty. If I try to navigate to /entries/(casual :id), I receive this error:
ActionController::UnknownFormat in EntriesController#index
and it highlights this part of the code:
def index
respond_with Entry.all
end
Why did I receive this error? How can I let Ruby on Rails communicate data with Angular JS? I am also adding my routes file:
Rails.application.routes.draw do
resources :entries
root to: "raffle#index"
end
Update your route.rb to render JSON by default instead HTML
resources :entities, defaults: {format: :json}
I'm currently working on this tutorial: AngularJS Tutorial: Learn to Build Modern Web Apps with Angular and Rails
In the tutorial project, users can create Blog Posts and Comments for those Posts. So far I've been able to create Blog Posts (which are saved into database), but when I try to create a Comment for a Post, then I get the following error:
Started POST "/posts/16/comments.json" for 127.0.0.1 at 2015-02-15 08:32:40 +0200
Processing by CommentsController#create as JSON
Parameters: {"body"=>"6", "author"=>"user", "post_id"=>"16", "comment"=>{"body"=>"6"}}
Comments create action entered... 6
Completed 500 Internal Server Error in 9ms
NameError (undefined local variable or method `post' for #<CommentsController:0xb6036e50>):
app/controllers/comments_controller.rb:6:in `create'
Note: line “Comments create action entered... 6
” is logger.info message.
Screenshot
comments_controller.rb
class CommentsController < ApplicationController
def create
logger.info "Comments create action entered... " + params[:body]
comment = post.comments.create(comment_params)
respond_with post, comment
end
def upvote
comment = post.comments.find(params[:id])
comment.increment!(:upvotes)
respond_with post, comment
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
posts_controller.rb
class PostsController < ApplicationController
def index
respond_with Post.all
end
def create
respond_with Post.create(post_params)
end
def show
logger.info "show action entered... " + params[:id]
#respond_with Post.find(params[:id])
#the code below works, the line above resulted in error: 406 (Not Acceptable)
render json: Post.find(params[:id]).to_json
end
def upvote
post = Post.find(params[:id])
post.increment!(:upvotes)
respond_with post
end
private
def post_params
logger.info "post_params entered..."
params.require(:post).permit(:link, :title)
end
end
In the PostsController's show action, I had previously changed line: respond_with Post.find(params[:id]) to: render json: Post.find(params[:id]).to_json because line: respond_with Post.find(params[:id]) produced error: GET http://0.0.0.0:3000/posts/4 406 (Not Acceptable)
I'm not sure, but the above issue might be related to internal error (500) message, why post is not found. Also if I use line: respond_with Post.find(params[:id]) in the PostsController then I still end up with the same problem with the Comment creation.
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
respond_to :json
def angular
render 'layouts/application'
end
end
routes.rb
FlapperNews::Application.routes.draw do
root to: 'application#angular'
resources :posts, only: [:create, :index, :show] do
resources :comments, only: [:show, :create] do
member do
put '/upvote' => 'comments#upvote'
end
end
member do
put '/upvote' => 'posts#upvote'
end
end
end
Below is post.js file that does the Ajax calls in which the o.addComment function's $http.post call tries to create the Comment in the following way: $http.post('/posts/' + id + '/comments.json', comment);
angular.module('flapperNews').factory('posts', ['$http',
function($http){
var o = {
posts: []
};
o.getAll = function() {
return $http.get('/posts.json').success(function(data){
angular.copy(data, o.posts);
});
};
o.create = function(post) {
console.log("o.create");
return $http.post('/posts.json', post).success(function(data){
o.posts.push(data);
});
};
o.upvote = function(post) {
return $http.put('/posts/' + post.id + '/upvote.json')
.success(function(data){
post.upvotes += 1;
});
};
o.get = function(id) {
return $http.get('/posts/' + id).then(function(res){
return res.data;
});
};
o.addComment = function(id, comment) {
console.log("addComment " + id + ", comments " + comment )
return $http.post('/posts/' + id + '/comments.json', comment);
};
o.upvoteComment = function(post, comment) {
console.log("o.upvoteComment " + post.id + ", comments " +comment.id)
return $http.put('/posts/' + post.id + '/comments/'+ comment.id + '/upvote.json')
.success(function(data){
comment.upvotes += 1;
});
};
return o;
}
]);
app.js
angular.module('flapperNews', ['ui.router', 'templates'])
.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home/_home.html',
controller: 'MainCtrl',
resolve: {
postPromise: ['posts', function(posts){
return posts.getAll();
}]
}
})
.state('posts', {
url: '/posts/{id}',
templateUrl: 'posts/_posts.html',
controller: 'PostsCtrl',
resolve: {
post: ['$stateParams', 'posts', function($stateParams, posts) {
console.log( "$stateParams.id " +$stateParams.id)
return posts.get($stateParams.id);
}]
}
})
$urlRouterProvider.otherwise('home')
}]);
My rails version is 4.0.2
Any help would be appreciated, because I've been struggling with the code for a couple of hours :-) Anyway, I'm glad that there is Stackoverflow forum where one can ask some advice :-)
First, this has nothing to do with angular. You don't have the post defined, so add:
post = Post.find params[:post_id]
also, i think your comment belongs_to post, you should set the post as the comment's post before saving the comment, so:
#comment.post = post
None of the tutorials I seem do what I'm trying to do. Very simply, I want a user to be able to submit a POST request to a controller (to "LIKE" a video) and have the controller respond back with a JSON object. Any help would be appreciated.
Thanks
EDIT Because SO is messing the formatting up, here is a gist of my code too:
https://gist.github.com/813503
Here is my controller:
class LikesController < ApplicationController
before_filter :get_ids
respond_to :json, :js
def videolink
results = {}
# check to see if the user has liked this videolink before
if current_user
liked = Like.video?(current_user, #vid_id)
results["status"] = "OK"
results["liked"] = liked
else
results["status"] = "Error"
results["message"] = "User not logged in"
end
respond_with( results.to_json )
end
def update
results = {}
if current_user
results["status"] = "OK"
else
results["status"] = "Error"
results["message"] = "User not logged in"
end
respond_with( results.to_json )
end
private
def get_ids
#vid_id = params[:videolink_id]
end
end
Here is my JS file:
$("#likeVideo").click(function() {
$.ajax({
contentType: "application/json",
data: { game_id: game_id, videolink_id: current_video["videolink"]["id"] },
dataType: "json",
type: "POST",
url: "/likes/" + game_id,
success: function(data) {
console.log("Success", data);
}
});
return false;
});
My routes:
resources :likes do
collection do
get "videolink"
end
member do
post :update
end
end
And here is the error I get:
NoMethodError
in LikesController#update
undefined method `{"status":"OK"}_url' for #<LikesController:0x0000010178be58>
If you want to send back custom JSON, Instead of respond_with(results.to_json)... just render the text
render :text=>results.to_json
The responds_with is a way for you to easily send back objects, with their location (url). So that's why your error is telling you that that '_url' is invalid.
More info on responds_with, courtesy of http://ryandaigle.com/articles/2009/8/10/what-s-new-in-edge-rails-default-restful-rendering
If another format was requested, (i.e.
:xml or :json)
If it was a GET request, invoke the :to_format method on the resource and
send that back
If the resource has validation errors, send back the errors in the
requested format with the
:unprocessable_entity status code
If it was a POST request, invoke the :to_format method on the resource
and send that back with the :created
status and the :location of the new
created resource
Else, send back the :ok response with no body