I followed Railscast Tutorial to set up mercury editor.
mercuy.js
$(window).bind('mercury:ready', function() {
var link = $('#mercury_iframe').contents().find('#edit_link');
Mercury.saveUrl = link.data('save_url');
link.hide();
});
$(window).bind('mercury:saved', function() {
window.location = window.location.href.replace(/\/editor\//i, '/');
});
views/quotations/show.html.erb
<p><%= link_to "Edit Page", "/editor" + request.path, id: "edit_link", data: {save_url: mercury_update_quotation_path(#quotation)} %></p>
mercury.html.erb
new Mercury.PageEditor(saveUrl, {
saveStyle: 'form', // 'form', or 'json' (default json)
saveMethod: null, // 'PUT', or 'POST', (create, vs. update -- default PUT)
visible: true // boolean - if the interface should start visible or not
});
routes.rb
resources :quotations do
member { post :mercury_update}
end
It shows the following error
Mercury was unable to save to the url: http://localhost:3000/quotations/1
Console output
Started PUT "/quotations/1" for 127.0.0.1 at 2015-03-07 19:20:49 +0530
AbstractController::ActionNotFound (The action 'update' could not be found for QuotationsController):
It worked well for static id's but not like this. Please help me to solve this error.
Your error is telling you
ActionNotFound
Meaning you are missing the mercury_update in your QuotationsController. Try adding
def mercury_update
quote = Quotations.find(params[:id])
quote.FIELD_FROM_YOUR_DB = params[:content][:quotation_content][:value]
quote.save!
render text:""#tells mercury of successful save (I think)
end
If that doesn't work, try checking your console for the the parameters mercury is passing around. It should look something like
Started PUT "/quotations/1/mercury_update" for ...
Parameters:{"content"=>{...}}
Notice that it is a PUT request, that's what Mercury is telling you that it's doing. Thus the route needs to be updated
resources :quotations do
member do
put 'mercury_update' #this may change your path to mercury_update_quotation_page_path(#quotation)
end
end
Also, ensure that resources :quotations is not defined twice in config/routes.rb. I defined it following that tutorial and then ran
rails g scaffold quotations
in order to auto-generate views and such. This command defined quotations again at the top of my config/routes.rb as
resources :quotations
#...
resources :quotations do #... This was my definition
thus ignoring my definition with the member 'mercury_update'.
Finally, let me know if your saved response is working, as mine is not. GL!
Related
I'm going a little crazy here as I'm at a real loss for words what is happening. After a lot of digging around, I believe I am doing everything as should be.
Situation
I'm trying to send a user creation form to the server via AJAX and codeIgniter fails to even get past this part
if($this->input->post('blnAjax')) { // do something }
I have successfully incorporated the AJAX side of things in to the client as it fetches content from the server with very little problem. Here are some of the details involved in the call:
Ajax code
The ajax code is part of a much larger framework beyond the scope of this question but in terms of the actual call function, the event has event.preventDefault(); event.stopImmediatePropagation(); to stop it running off. The URL is reachable and the post values have been serialized with request type set to POST
requestpage: function(){
var strURL = params.strBaseURL + params.strRequestURL;
$.ajax({
type: params.strRequestMethod,
url: strURL,
data: params.strRequestParameters,
dataType: 'json',
success: function(json) {
methods.postrequestprocedure(json);
}
});
},
Ajax request
Everything runs smoothly on the client making the XMLHttpRequest with json as expected return. I don't even get to this point when the form has been submitted however. Codeigniter will never think the form has been set if using AJAX
Parameters application/x-www-form-urlencoded
blnAjax 1
user_login_name[] fred
user_login_name[] ted
user_name[] Fred Flintstone
user_name[] Ted bear
usergroup_id[] 16
usergroup_id[] 16
Controller
On the controller, with regard to the action, I have included alall code up to the point of fail. Please note that I have tested the other aspects of the code and they run fine
public function user_add() {
/* Include extra script files needed for form handling */
$this->view['aryScript'][] = 'jquery.validate.min';
$this->view['aryScript'][] = 'jquery.validate.additional-methods';
/* Include extra CSS files */
$this->view['aryCSS'][] = 'form';
/* First check if the user has correct access rights */
if($this->view['intAccessLevel'] < INT_SUPER_USER_ACCESS_LEVEL) {
$aryResponse['notifications'][] = array('strType' => 'permanent',
'strMessage' => 'Denied!');
}
/* Import extra libraries and helpers */
$this->load->library(array('PasswordHash'));
$this->load->model('UserAdminModel');
$this->view['strTitle'] = 'Add User';
$this->view['aryButtons']['user_add_another'] = array(
'strDisplay' => $this->lang->line('user_add_another')
'strURL' => '#',
'strID' => 'user_add_another',
'aryData' => array('action' => 'form-clone')
);
if($this->input->post('blnAjax')) {
echo 'Big sigh of relief';
Thank you kindly for taking the time to read my problem
The answer is never as simple as it seems! My client is using a CodeIgniter mod that rewrites the URI and thus dumping the data passed from the ajax query. It hadn't been a problem when performing gets and "real" POST queries.
So if you are ever using Wiredesignz - Language Identifier beware that it can affect your queries
How I fixed it, I use a custom page controller but the theory is the same:
Be sure that you have $this->config->item('language_abbr'); available to your javascript functions maybe through a constant or echo it directly in to the javascript if on the same page
Modify the URL before sending it with something similar to params.strBaseURL + params.strLanguage + '/' + params.strRequestURL;
You should now find things work just fine. I hope this helps and noone else has to spend a mini eternity to find this out
So I've implemented the Markitup bbcode editor in my Rails application and I'm currently attempting to get the preview functionality working. I followed a 4 year-old blog entry install markitup! in Ruby on Rails which got me pretty close to what I need to do. So far, when I press the preview button it renders an iframe that displays a blank template for me.
In my jquery.markitup.js I have this line as one of the options:
previewTemplatePath: '/templates/preview',
Which will make an ajax request to retrieve the page for the route:
resources :templates do
collection do
get :preview
end
end
Currently the preview action simply sets render :layout => false so I don't duplicate html. As for the preview.html.erb page itself I simply have:
<%= bb(params[:data]) %>
And the idea behind this is to send the markup entered in the editor into the params data hash and then pass that through my bb code helper which does the parsing and returns some html.
The Problem
I don't know how to fill that params[:data] with the bb code entered into the markitup editor. Does anybody know how I can send that off?
Extra details:
I thought I would include all the options I'm passing off to markItUp:
options = { id: '',
nameSpace: '',
root: '',
previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes'
previewAutoRefresh: true,
previewPosition: 'after',
previewTemplatePath: '/templates/preview',
previewParser: false,
previewParserPath: '',
previewParserVar: 'data',
resizeHandle: true,
beforeInsert: '',
afterInsert: '',
onEnter: {},
onShiftEnter: {},
onCtrlEnter: {},
onTab: {},
markupSet: [ { /* set */ } ]
};
The previewTemplatePath and the previewParserPath options needed to be set when I make the call to markItUp!.
The previewTemplatePath points to the view that displays the rendered preview and the previewParserPath is meant to point to your controller action that handles the parsing and data parameter. Assuming you're following dry conventions both paths should be the same as it was in my case.
For a better look at how to integrate markItUp! with rails check out the source for branch14's markupitup gem.
I'm using Node.js, Express and Jade and I'm trying to figure out how to post, validate & process form data.
In my jade file I create a contact form:
div#contact-area
form(method='post',action='')
label(for='name') Name:
input(type='text',name='name',id='name')
label(for='email') Email:
input(type='text',name='email',id='email')
input(type='submit',name='submit',value='Submit').submit-button
I'm then utilising the module 'express-validator' to validate the form as follows:
var express = require('express')
,routes = require('./routes')
,http = require('http')
,path = require('path')
,expressValidator = require('express-validator')
;
var app = express.createServer();
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade'); //not needed if we provide explicit file extension on template references e.g. res.render('index.jade');
app.use(express.bodyParser());
app.use(expressValidator);
app.use(express.methodOverride());
app.use(app.router);
});
//display the page for the first time
app.get('/mypage', function(req,res){
res.render('mypage', {
title: 'My Page'
});
});
//handle form submission
app.post('/mypage', function(req,res){
req.assert('name', 'Please enter a name').notEmpty();
req.assert('email', 'Please enter a valid email').len(6,64).isEmail();
var errors = req.validationErrors();
if( !errors){
sendEmail(function(){
res.render('mypage', {
title: 'My Page',
success: true
});
});
}
else {
res.render('mypage', {
title: 'My Page',
errors: errors
});
}
});
So there are three scenarios where my pages is rendered, and each one has access to different local variables:
When the page is loaded for the first time (errors=undefined,success=undefined)
When the form is submitted and there are errors (errors=array,success=undefined)
When the form is submitted and there are no errors (errors=undefined,success=true)
So my main problems are that:
When my Jade page is loaded, it seems to throw an error when I attempt to access a variable that doesn't exist. For example, I want to see if the variable 'success' is set, and if it is I want to hide the form and display a "thanks" message. Is there an easy way to handle a variable in Jade that will either be undefined or a value?
When the form has been submitted and there are validation errors, I want to show an error message (this isn't a problem) but also populate the form with the variables that were previously submitted (e.g. if the user provided a name but no email, the error should reference the blank email but the form should retain their name). At the moment the error message is displayed but my form is reset. Is there an easy way to set the input values of the fields to the values in the post data?
You can fix that by using locals.variable instead of just variable. Also you can use javascript in jade.
-locals.form_model = locals.form_data || {};
I used two ways to solve this problem. The first one is to re-render the view and you pass the req.body as a local. I have a convention that my forms use form_model.value for their field values. This method is works well for simple forms but it starts to breakdown a little when you form is relying on data.
The second method is to pass your req.body to session then redirect to a route that renders the form. Have that route looking for a certain session variable and use those values in your form.
Inside your jade file add error msg and then run your code.
Simply update your jade code with below code:
div#contact-area
ul.errors
if errors
each error, i in errors
li.alert.alert-danger #{error.msg}
form(method='post',action='')
label(for='name') Name:
input(type='text',name='name',id='name')
label(for='email') Email:
input(type='text',name='email',id='email')
input(type='submit',name='submit',value='Submit').submit-button
I use spine.js in conjunction with the Spine.Ajax Module to load stuff via JSON from the Server. I've probably run into some syncronisation problem. I have a sidebar which just binds to the refresh and change events and then is rendered:
Survey.bind 'refresh change', #render
I also have set up some routes, which display a survey when the user accesses it via #/survey/:id. This is my controller:
class App.Surveys extends Spine.Controller
className: 'surveys'
constructor: ->
super
#append(#sidebar = new App.Sidebar) # Sidebar to select surveys
#append(#surveys = new App.SurveysStack) # Show survey details survey
#routes
'/surveys/:id': (params) ->
#sidebar.active(params)
#surveys.show.active(params)
Survey.fetch()
As you see, Survey.fetch() is called after the initialization, which does not pose a problem to the sidebar. However, it seems, that it poses a problems to the surveys Show controller (which is called by a Spine.Stack called App.SurveyStack):
class Show extends Spine.Controller
constructor: ->
super
#active #change
change: (params) =>
# There is a bug! If Survey is not fetched when we run this,
# this throws an error.
#item = Survey.find(params.id)
#render()
render: ->
#html #view("surveys/show")(#item)
I keep getting errors from the commented part of the source: Uncaught Unknown record. Can I make the Survey.find() function block until Survey.fetch() is done?
You are correct in your diagnosis that you can't find an item before you've fetched it from the server.
The easiest solution is to bind an event to the Survey.fetch() call like so:
Survey.bind 'refresh change', #method_to_call
Let me know if that helps!
Actually the solution that worked for me is to initialize the Spine.Route.setup() after the object has refreshed. Instead of the standard call in app/index.js.coffee, it would be:
App.Survey.one 'refresh', ->
Spine.Route.setup()
I'm trying to add some Ajax functionality in my Rails 3 app.
Specifically, I want a button that will submit an Ajax request to call a remote function in my controller, which subsequently queries an API and returns a JSON object to the page.
Once I receive the JSON object I want to display the contents.
All of this with the new Rails 3 UJS approach, too. Is there a good example/tutorial for this online somewhere? I haven't been able to find one on google. A simple example using a button as the entry point (ie, the user clicks the button to start this process) would work, too.
Edit
Let me try this with a different approach. I want to have this button query an external API, which returns JSON, and display that JSON on the page. I have no idea where to even begin. Does the button itself query the external API? Do I need to go through the controller, and have the controller query the external API, get the JSON, and give the JSON back to this page? How do I display/access the contents of this JSON? I honestly can't find a good Rails 3.x example of how to handle JSON...
Here is a start:
First create your button with a link_to method in your view, for example:
=link_to "delete", "#{invitation_path(invitation)}.json", :method=>:delete, :remote=>true, :class=>"remove", :confirm=>'Are you sure you?'
Note that I am appending ".json" to the url of my resource. This is just an example of a an AJAX delete, google link_to to see the meaning of the parameters. The concept if that you make your HTTP request with the parameter :remote set to true, in other words this is translated to an AJAX call from your browser.
Second, write some javascript so that you can process what ever is the result of the AJAX call your browser will make when the user click on the link_to of step 1. For details you can see this blog post: http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
An example from my site:
jQuery(function($) {
// create a convenient toggleLoading function
var toggleLoading = function() { $("#loading").toggle() };
$("#pending_invitation")
.live("ajax:loading", toggleLoading)
.live("ajax:complete", toggleLoading)
.live("ajax:success", function(event, data, status, xhr) {
var response = JSON.parse(xhr.responseText)
if (response.result == "ok") {
$(this).fadeOut('fast');
}
else {
var errors = $('<div id="error_explanation"/>');
errors.append('<h2>Pending invitation action error</h2><ul><li>' + response.error + '</li></ul>');
$('#new_invitation_error').append(errors)
}
});
});
where you can see that I parse the returned json and and change the html on the page based on that. Note that this js uses the CCS ids and classes defined in the top view that is not included here.
If you now want to write you own controller to spit out the json here is an example:
class InvitationsController < ApplicationController
respond_to :html, :json
# other methods here
# ...
def destroy
#invitation = Invitation.find(params[:id])
respond_to do |format|
if #invitation
#invitation.destroy
flash[:success] = I18n.t 'invitations.destroy.success'
format.json { render :json =>{:result => "ok", :message=>"Invitation #{params[:id]} was destroyed", :resource_id=>params[:id] } }
else
format.json { render :json => { :result=>"failed", :error=>"Cannot find Invitation #{params[:id]}", :resource_id=>params[:id] } }
end
end
end
end
Hope this help.
Old question, but a really good overview of Ajaxifying Rails applications is:
Ajax in Rails 3.1 - A Roadmap
Also consider returning errors in the following format:
render :json => #myobject.to_json, :status => :unprocessable_entity
This will ensure that your client can process the response as an error.