How to PATCH or DELETE from a form without javascript - phoenix-framework

I am writing a simple crud app on Phoenix. How does one submit PATCH and DELETE requests from a form without using javascript?

Ah I figured it out, same as rails:
<form method="POST">
<input name="_method" type="hidden" value="patch" />
...
Handled in Plug.MethodOverride: https://github.com/elixir-lang/plug/blob/master/lib/plug/method_override.ex

<form> elements only support sending GET and POST requests. The workaround that Rails uses is to read the request method from the _method request parameter, overriding the actual request method (the GET or POST method).
Phoenix does exactly the same through Plug, the Rack-like framework that Phoenix is built on. Long story short, Plug provides middlewares and one of the middlewares it provides is Plug.MethodOverride, which does exactly what we discussed. Doing so in a middleware, the Phoenix app barely knows that the original request was not a GET/POST.
You can see Plug.MethodOverride used in Phoenix's source code.

As the others have mentioned, Phoenix handles this in the routing via the MethodOverride plug.
In order to change this in the template with the form_for helper, use the :method parameter:
<%= form_for #changeset, path(#conn, :update), [multipart: true, method: "patch"], fn f -> %>
This will add the hidden input to the HTML, as noted by #greggreg:
<input name="_method" type="hidden" value="patch" />

Related

Spring Framework + Thymeleaf: How to call a ModelAndView method every few seconds/Scheduled task

I'm using Spring Framework with the Twitter's API, and I have a method to get tweets related with hashtags.
This method is called from the view using a th:action with a th:object and th:field from where I get the hashtags for the query.
In the controller, I have a ModelAndView method, which receives the "hashtags" and gets tweets and returns to the same view but now with a List filled with these tweets.
Is there any way that when I press the button the method call itself every x seconds until I press another button or I call another method? (To filter the current list of tweets for example or to do a new search).
I know there is an annotation #Scheduled but it needs a non-parameter method, and also I need to repeat a method at certain part of the execution, not from the start of it.
I know it's a basic idea, but anyway, i'm going to leave a picture with what I have programmed (top), and what I'm trying to get (bottom)
This is the view:
<form class="navbar-form navbar-left" action="#" th:action="#{/twittercontrolador/buscartuits}" th:object="${textoplano}" method="post">
<div class="row">
<div class="form-group">
<b>Hashtags/Menciones:</b> <input type="text" class="form-control" placeholder="Max 5 - #asdf / #nick" th:field="*{texto}" />
<button type="submit" class="btn btn-primary" value="Buscar">Buscar</button>
</div>
</div>
</form>
And here the controller (Just a #controller, spring controller page)
#PostMapping(value="/buscartuits")
public ModelAndView obtenerTuits(#ModelAttribute("textoplano") TextoEnPlano texto){
ModelAndView mav = new ModelAndView("vistaPrincipal");
String resultadoBusqueda = this.textoBusqueda(texto.getTexto());
List<Tweet> listaTuits = twitter.searchOperations().search(resultadoBusqueda).getTweets();
listaPropia = new ArrayList<ObjetoTuit>();
int contAux = this.listaDe5Elementos.getNumElementos();
for(int i=0; i<listaTuits.size();i++){
...
}
mav.addObject("listaobjetostuits", listaPropia);
return mav;
}
I've tried using this:
https://spring.io/guides/gs/scheduling-tasks/ but this seems not to be right for me
Its just Java code in the end. Don't you want it connected to the front end though? If yes use setTimeout in the client html. If you want to do something in the back end only, can use spring batch or a java thread (not recommended but will work if you do it correcrly and there are not too many other threads being started in your code).
What code have you tried ? When you say Controller you mean a REST API call? Or is it a JSP or spring controller page?
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html we dont use this on a controller -> usually at the service/ facade layer of the back end. Like for a background job to be done.
If your doing it from the HTML can use https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout Javascript code
You can use cron to all a URL every x time units.
You can use a HTTP library to call your URL programmatically, that can have a authenticaiton (login) step and then call you Controller steps. Then use scheduler to make it happen at some repeated way. Spring has a HTTP library, or can use Apache Http Components, or OkHttp or java.net.URL depending on complexity of the page and what works in your case. I have used all.
Can even use Jmeter - via the API or programmatically.
You can make a selenium to programmatically open a browser and do actions like logon, open a page, fill & submit a form, on the system where the selenium code runs. Then use scheduler in this app.
First you need to define your problem and what exactly you have tried better.
And do more research using the alternatives I have listed.

FormUrlEncodedMediaTypeFormatter vs JQueryMvcFormUrlEncodedFormatter

I have created a default web api project with at least those 2 media formatters loaded. Both are for the same content-type:
FormUrlEncodedMediaTypeFormatter: application/x-www-form-urlencoded
JQueryMvcFormUrlEncodedFormatter: application/x-www-form-urlencoded
When I do a simple http post form with enctype="application/x-www-form-urlencoded" it works only with the JQueryMvcFormUrlEncodedFormatter, that means my sent complex object is not null at server side.
When I remove the formatter JQueryMvcFormUrlEncodedFormatter at application startup and do the simple http post form again I expect it to work again but it does not.
I get an exception that no appropriate formatter is loaded.
Thats not true -actually-
Why does it not work?
P.S.
I found that this is the difference:
– System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter, for handling HTML form URL-encoded data
– System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter, for handling model-bound HTML form URL-encoded data
but I do not understand the difference!
I do not even use jquery to post my form:
<form role="form" method="post" action="api/values" enctype="application/x-www-form-urlencoded">
<input type="text" class="form-control" name="firstName" placeholder="Enter first name">
<input type="text" class="form-control" name="lastName" placeholder="Enter last name">
<button type="submit" class="btn btn-default">Submit</button>
</form>
FormUrlEncodedMediaTypeFormatter binds application/x-www-form-urlencoded body to FormDataCollection type, and only that type.
JQueryMvcFormUrlEncodedFormatter however uses available ModelBinders to first parse the body to FormDataCollection and then use the first compatible ModelBinder to parse that into the final model. It's like mixing Model Binding approach and Media Type Formatting approach, which AFAIK is not explained anywhere in the WebAPI docs.
Both formatters are registered by default. This is what I inferred reading WebAPI source code.
There are 4 out of box formatters
JsonMediaTypeFormatter
XMLMediaTypeFormatter
FormUrlEncodedMediaTypeFormatter
JQueryMvcFormUrlEncodedFormatter
The first two media type formatters can serialize and deserialize CLR types to request/response and vice versa. But 3rd one neither serializes nor deserializes to/from any CLR type. 4th formatter can deserialize incoming raw data to CLR type.
Hence in your case, you are experiencing with error after you remove JQueryMvcFormUrlEncodedFormatter since 3rd formatter could not able to deserialize incoming request data to CLR type.

ruby/erb/cgi -- get method works, but post doesn't

I am trying to write a simple eruby (erb) cgi form. Everything works fine, if I use method="get". For example, the following code just dumps the cgi parameters.
<html><body>
<% require 'cgi' %>
<% cgi = CGI.new %>
<%= cgi.keys %>
<form action="/sscms/temp.rhtml" method="get">
<input type="text" name="title" value="Grover">
<input type="submit" value="save">
</form>
</body></html>
However, if I change "get" to "post", the cgi parameters are always empty. This seems to work with plain-old ruby cgi. So it appears to be an eruby/cgi problem. Everything I've seen online seems to say that get and post are treated the same by ruby. Is there something I am missing?
Thank you.
"a CGI program is called with the parameters of the request passed in either in the environment (GET) or via $stdin (POST)", you can only consume $stdin once but you can read the environment as many times as you want.

Sending a DELETE request from Sinatra

I am trying to develop a RESTful Sinatra application. Now, I know how to respond to a delete request with something like
delete '/user/:id' do |id|
#do something in the model
end
What I am interested in is how do I get to execute that method. I can't have link that does a DELETE instead of a GET, can I?
The only solution I found so far is sending a DELETE request via jQuery: How to send a PUT/DELETE request in jQuery?
I tried looking into different RESTful Sinatra projects on github but my Ruby knowledge is probably to limited to get how they are doing it.
Put following line in your code.
use Rack::MethodOverride
It will help you interpret post methods with parameter "_method" with value "delete" as put.
Then you can write
delete '/user/:id' do |id|
I thinks it's like the Rails way. You need define a params '_method' with 'delete' value and add it on your form.
When you POST you form with this particular params, you do a DELETE request in sinatra.
Like :
<form action="/search" method="post">
<div style="margin:0;padding:0">
<input name="_method" type="hidden" value="delete" />
</div>
</form>
It's the same with PUT method
Another way is to use Curl:
curl -X DELETE http://host/user/1
%form{:action => "/note/delete/#{#note.id}", :method => "post"}
%input{:type => 'submit', :name=> "_method", :value => 'delete', :class => 'button'}
You can also trigger the delete route with a button like so
see also Call Sinatra delete route with jQuery for how to do this with jQuery and JSON at the front end and Sinatra on the back end.

Codeigniter: Pass form variable into URI

Not sure if this can be done but it seems my main issue is because i have a default route to a method called "index." I want to be able to list all users tagged with a specific keyword. In addition, users can search for other users based on these keywords.
i.e.
www.domain.com/tags/apples
www.domain.com/tags/oranges
www.domain.com/tags/blueberry
It works fine if I go to the URL manually. I'm having issues getting it to work with a form field.
Snippet of the form_open:
<?=form_open('tags/');?>
<p>Search for Tag: <input type="text" name="tag" /></p>
<p><input type="submit" value="Search" /></p>
Here's a snippet of my controller:
function index() {
$data['result'] = $this->tags_model->searchByTag($this->uri->segment(2));
$this->load->view('tags_view', $data);
}
Here's a snippet of my router:
$route['tags'] = "tags/index";
$route['tags/(:any)'] = "tags/index/$1";
Now, I can easily fix all this if I have a method called search, but I don't want the URL to show up as www.domain.com/tags/search/orange.
When you create your form you set it to use POST variables instead of GET, that way they don't go through the url, that's codeigniter's default method for forms.
So your form_open code will generate the following code:
<form method="post" action="tags/" />
If you want them to got through url though, call the form opener this way instead:
form_open('tags/', array('method' => 'get'));
The same applies to any other attributes you want to specify for the form, just follow the same pattern attribute_name => attribute_value inside the array.
More info on the user guide
The problem here is that your form will be submitting all it's data to "/tags", with nothing trailing it, as POST data doesn't come in as part of the URL. Even if it was a GET request however, I don't think that CodeIgniter will take anything out of the querystring and use it as part of the routing segments.
I think what you should do is have a small Javascript function that automatically updates the form action parameter to be tags/<select option value> whenever the select value is changed. This way it will submit to the right place. In order to handle non-javascript enabled browsers, you could have a default action called tags/search that would simply analyze your form data and put out a 301 redirect to the proper tags/<location> once you'd figured it out.
It seems like a bit of overkill here however, as you could really point the form at tags/index and not worry about it. I'm not sure search engines index form submission locations, and even if they did, they certainly wouldn't index a form that submits to dynamic URIs in the way that you want it to. You could still link to the search result pages using tags/apples, etc, but the form could work quite normally just by going to tags/index.
I ended up redirecting the URL and passed the keyword into the URI.
i.e. domain.com/tags/view/

Resources