#do a cols database web upload
Explore tagged Tumblr posts
mllemouse · 5 years ago
Text
I am so fucking tired
5 notes · View notes
nullset2 · 8 years ago
Text
How to model Posts with Tags (Grails 3 example)
A common use case which I haven't seen covered elsewhere is how to model a Post to Tag association when developing a relational database-backed Application (whether of the Web persuasion or otherwise)
This comes in handy when developing software where you want to allow people to upload and share pieces of content (from here onwards referred to as Posts) associating those pieces of content with metadata for some kind of trend or reporting purpose (from here onwards referred to as Tags). For example: blog posts.
I want to share my technique in case anyone needs to do something similar, in this case, with Grails 3. However the knowledge disclosed here is applicable to any other way to structure your application.
Introduction
Now then, a quick refresher: Grails allows you to easily code an MVC stack using groovy, a (beautiful) language for the JVM, to develop an application.
By MVC stack I mean that your repository will have fully working pieces of logic related to the model, view and controller layers of web applications.
It may sound complicated for newbies, but all that I'm talking about is that by using grails we're strongly following a design principle called separation of concerns, which establishes that certain parts of your code should only have a single, certain, intended purpose.
The clear advantage of this is that it makes your systems layerized and easy to grok in the long term. It also helps replacing parts of your system for better parts (for example, a new, optimized templating engine in place of your old one, faster data structures, or a better ORM, to say the least)
Also, when combined with the convention-over-configuration school of thought that Grails and other such frameworks adhere to, this results in humongous productivity and an elevated level of agility in your response as a developer.
The Schema
So back on track: to model posts with tags, we need two models (which grails calls domain classes), one for Post, and one for Tag. Then, the relationship between both becomes obvious: whenever you publish a post, you can associate many (or no) tags to it. So then it is said that each tag can belong to many posts.
Remember you can get nice empty domain classes by using a command such as grails create-domain-class Post.
The way that I see it, each post should, to begin with, at least have a title and content, where the first one should be a string of sensible length, and the second should be something more robust (postgres has a text type which I like, and a tag should be defined by a name. We can add other fields in the database besides that for some housekeeping too :D
You may already be well knowledgeable that to associate one database-backed model to another (or, rather, to associate records on a relational database) in a many to many relation, you need something that is called a join table, which consists of a series of records constituted by two foreign keys, both pointing to the primary keys of their respective tables.
In our case we can determine a join table called post_tags which relates a post_id foreign key pointing at the posts table with a tag_id foreign key pointing at the tags table. Then, whenever you need your relationships you can simply query this table on the database.
This is a quick and dirty schema that describes this database:
The thing is, that with grails, getting this is a simple as expressing as coding your domain classes in a certain way:
package blog class Post { String title String content Date dateCreated Date lastUpdated static hasMany = [tags: Tag] static mapping = { content type: "text" } static constraints = { title maxSize: 255, blank: false content blank: false } }
package blog class Tag { String name Date dateCreated Date lastUpdated static belongsTo = Post static hasMany = [posts: Post] static constraints = { name maxSize: 30, blank: false, unique: true } String toString(){ name } }
Notice, in both cases, the presence of static hasMany and belongsTo class members. These link your two domain classes in a snap. The good thing is that grails will also know how to create the join table for both models and will indeed do it automatically on your database.
The view
So, assuming you have your domain classes in check now it's time to create nice views for your stuff.
If you scaffold your views and controllers with grails generate-all you will now notice that your create view for Post are now prepared with a hasMany record selector:
Which will send the ids of your selected options (on a computer you can ctrl-click the elements of the selector) to your controller, where GORM will process them into nice join table records, all automagically. In this way your Post domain will maintain itself updated with its associated Tags.
Again, this is all provided by the framework! Oh joy! Right?
Well, so what if you want to replace the multiselect with some other kind of UI element? Something that comes to mind is checkboxes. Checkboxes are a pretty natural way to tell your application that you want to add n different associated records to your Post, and simpler to use than the selector.
So to do that you can dig into your grails-app/views/post directory and let's isolate the code representing the model form for the Post domain into its own partial. The last few tags before closing longest-enclosing div will create checkmarks per each Tag you currently have on your database and will show them checked if and only if an association has already been persisted, and otherwise if the relationship is available but doesn't exist yet:
<%@ page import="blog.Post" %> <%@ page import="blog.Tag" %> <div class="fieldcontain ${hasErrors(bean: post, field: 'title', 'error')} "> <label for="title"> <g:message code="post.title.label" default="Title" /> </label> <g:textField name="title" value="${post.title}" /> </div> <div class="fieldcontain ${hasErrors(bean: post, field: 'content', 'error')} "> <label for="title"> <g:message code="post.content.label" default="Content" /> </label> <g:textArea name="content" value="${post.content}" rows="30" cols="160" class="big-textarea"/> </div> <div class="fieldcontain"> <g:each in="${Tag.list()}" var="tag"> <label>${tag.name}</label><g:checkBox name="tags" value="${tag.id}" checked="${post.tags.find { it.id == tag.id }}" /> </g:each> </div>
The partial should be saved to the same directory that the create.gsp file is saved to and its name should begin with an underscore, such as _form.gsp. Then you can just invoke the partial with a very simple directive on the create.gsp and edit.gsp templates with a very simple g:render statement: ``. If you're familiar with ruby on rails partials, this should come second nature, all nice and easy.
GSP?
A quick refresher on GSP: GSP stands for Groovy Server Pages and it's the name of the template engine for the Grails ecosystem. It's the Grails analogous of JSP, ERB, Jade, Haml, Slim, or whatever other templating engine you like. Through succint combination of binding of objects to view patterns, and by providing you the ability to compose views with the template engine by reusing smaller snippets of code over and over, you can instruct the grails runtime on how to produce really nice HTML documents on the fly whenever a user requests it. This takes very little time and is done very easily, and without having to write any heavy front-end code. This can work wonders for some apps, depending on the level of UI design and UX focus that you have. Some other apps may prefer to go for a SPA kind of approach and throw some fancy schmanzy javascript framework in there that consumes and provides data as JSON or XML documents from and to a RESTful or SOAP API, and those are very exciting domains of course, however just bear in mind that grails helps us solve those problems faster.
Bring it home
So finally after remembering about GSP, keeping in mind that there's plentiful documentation for GSP elsewhere and that any html tags beggining with g: are actual backend code that will get process by your runtime, we can form our partial such as this:
Where we're basically telling the backend to give us checked checkboxes for each record of Tag that corresponds to an already existing join_table record for posts to tags, and otherwise draw available checkboxes for all those who aren't.
And now not only should you have a kind of nicer post create form, but actual checkmarks in your code!
So, cool, right? you have a quick and dirty working blog which should had only taken you the most of an hour to pull off... I hope you like it and send me any questions you may have!
1 note · View note
mbaljeetsingh · 8 years ago
Text
Uploading Images to Cloudinary with Laravel (sponsor)
Sponsor / November 13, 2017
Uploading Images to Cloudinary with Laravel (sponsor)
Images are an essential part of any web application. They have the power to create an emotional response in the audience, which is worth its weight in gold. Our brain is designed to interpret images much quicker than text, so when developing a website, it is imperative to take your images seriously.
In this tutorial, I will introduce you to image services offered by Cloudinary for uploading images in Laravel. We will focus on uploading images to the Cloudinary server in Laravel application.
Cloudinary is the end-to-end image and video management solution, which also offers robust, highly reliable cloud storage for all your media.
What We will Build
In this tutorial, we will upload images to Cloudinary using jrm2k6/cloudder package. This package will do the heavy lifting for us and make it easy to interact with Cloudinary API.
Sign up For a Free Cloudinary Account
Before we start installing Laravel, go to Cloudinary and sign up for a free Cloudinary account.
This will give you the necessary credentials to access and interact with Cloudinary functionalities. Once you have signed up, log in and view your dashboard. It should be similar to this:
Take note of your account details Cloud name, API Key, API Secret because you will need them within your .env file:
CLOUDINARY_API_KEY = 'Your key' CLOUDINARY_API_SECRET = 'Your secret' CLOUDINARY_CLOUD_NAME = 'Your cloud name'
You are almost ready to start utilizing some of the amazing services and functionalities offered by Cloudinary.
Install Laravel
Laravel utilizes Composer to manage its dependencies. So before using Laravel, make sure you have Composer installed on your machine.
You can download and install Laravel via:
Laravel installer
Composer create-project.
For the sake of this tutorial, let’s proceed by using the second option. So run :
composer create-project --prefer-dist laravel/laravel laravel-upload-tut
This will create a Laravel project called laravel-upload-tut in your development directory.
Next, install jrm2k6/cloudder package using composer:
composer require jrm2k6/cloudder:0.4.*
Now open config\app.php file and add the following service provider and aliases in respective array:
'providers' => array( 'JD\Cloudder\CloudderServiceProvider' ); 'aliases' => array( 'Cloudder' => 'JD\Cloudder\Facades\Cloudder' );
Run the following command to publish:
php artisan vendor:publish --provider="JD\Cloudder\CloudderServiceProvider"
The command above will generate a cloudder configuration file for you in the following path config/cloudder.php
You can change the following settings (optional) with corresponding values from your dashboard:
CLOUDINARY_BASE_URL CLOUDINARY_SECURE_URL CLOUDINARY_API_BASE_URL
Start the PHP’s built-in development server to serve your application:
php artisan serve
Creating a Controller and Route
We are getting close; the next thing is to create a controller that will handle the image upload request:
php artisan make:controller ImageUploadController
Open app\Http\Controllers and add :
<?php namespace App\Http\Controllers; use JD\Cloudder\Facades\Cloudder; use Illuminate\Http\Request; class ImageUploadController extends Controller { public function home() { return view('home'); } }
This function will render the view for uploading our images. We will create this view in a bit. To handle image upload, let’s add another function uploadImages()
<?php ... class ImageUploadController extends Controller { public function home() { ... } public function uploadImages(Request $request) { $this->validate($request,[ 'image_name'=>'required|mimes:jpeg,bmp,jpg,png|between:1, 6000', ]); $image_name = $request->file('image_name')->getRealPath();; Cloudder::upload($image_name, null); return redirect()->back()->with('status', 'Image Uploaded Successfully'); } }
Here, we handled validation of an uploaded image and ensured that the file size is between 1kb and 6000kb. Then we used Cloudder::upload($image_name, null) to handle the actual upload of the image to Cloudinary account.
For the upload routes, open routes/web.php file and add the following:
<?php Route::get('/', 'ImageUploadController@home'); Route::post('/upload/images', [ 'uses' => 'ImageUploadController@uploadImages', 'as' => 'uploadImage' ]);
The next thing to do is to create a view file for our example application. So head over to resources/views and create home.blade.php file. Fill it with :
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width"> <title>Cloudinary Image Upload</title> <meta name="description" content="Prego is a project management app built for learning purposes"> <link rel="stylesheet" href="http://ift.tt/2apRjw3"> <link rel="stylesheet" href=""> </head> <body> <div class="container" style="margin-top: 100px;"> <div class="row"> <h4 class="text-center"> Upload Images </h4> <div class="row"> <div id="formWrapper" class="col-md-4 col-md-offset-4"> <form class="form-vertical" role="form" enctype="multipart/form-data" method="post" action=""> @if(session()->has('status')) <div class="alert alert-info" role="alert"> </div> @endif <div class="form-group"> <input type="file" name="image_name" class="form-control" id="name" value=""> @if($errors->has('image_name')) <span class="help-block"></span> @endif </div> <div class="form-group"> <button type="submit" class="btn btn-success">Upload Image </button> </div> </form> </div> </div> </div> </div> </body> </html>
To spice our page up a little, let’s add navigation:
<!DOCTYPE html> <html> <head> ... </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Cloudinary Image Upload</a> </div> </div> </nav> ... </body> </html>
You will notice that we included a stylesheet in the home.blade.php file. Let’s now create public/css/style.css and add:
#formWrapper { border: 2px solid #f5f5f5; padding: 20px; }
By now, your page should look similar to this:
You can go ahead and upload any image now.
There you have it, uploading images to Cloudinary from the Laravel application is as simple as that.
##Bonus: Persisting Image Delivery URLs
The objective of this tutorial was to show you how to upload images to Cloudinary using Laravel. We have been able to achieve this already, but you might want to save the URL of the uploaded image in your database and be able to view all of them, as well.
Let’s create a model for this purpose. The fastest way to create a model is to use the following command, with a parameter that you can use to specify the model name. So in our case, we will create an Upload model.
php artisan make:model Upload -m
Once you are done, you will find a new file as app/Upload.php and migration file associated with the model for our database schema.
Now open the migration file generated and edit it to reflect our database schema:
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUploadsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('uploads', function (Blueprint $table) { $table->increments('id'); $table->string('image_name'); $table->string('image_url'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('uploads'); } }
##Database Set Up Open the .env file and add your database details
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=Your-database-name DB_USERNAME=Your-database-username DB_PASSWORD=Your-database-password
##Migrating and Creating Table You can go ahead and run the migration with:
php artisan migrate
If you hit the following error when trying to run the migration command, it’s because you are running an older version of MySQL:
[PDOException] SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
You can read more about it here. But a quick fix is to drop the database and re-create it. Then you have to edit your AppServiceProvider.php file and set a default string length inside the boot method:
use Illuminate\Support\Facades\Schema; public function boot() { Schema::defaultStringLength(191); }
You can now run the migration command again and everything should be fine.
In order to obtain and save the image URL uploaded to Cloudinary, we will need to edit the logic within ImageUploadController. So can go ahead and replace uploadImages() function with this:
public function uploadImages(Request $request) { $this->validate($request,[ 'image_name'=>'required|mimes:jpeg,bmp,jpg,png|between:1, 6000', ]); $image = $request->file('image_name'); $name = $request->file('image_name')->getClientOriginalName(); $image_name = $request->file('image_name')->getRealPath();; Cloudder::upload($image_name, null); list($width, $height) = getimagesize($image_name); $image_url= Cloudder::show(Cloudder::getPublicId(), ["width" => $width, "height"=>$height]); //save to uploads directory $image->move(public_path("uploads"), $name); //Save images $this->saveImages($request, $image_url); return redirect()->back()->with('status', 'Image Uploaded Successfully'); }
And add this new method to persist the image URL and name into the database:
public function saveImages(Request $request, $image_url) { $image = new Upload(); $image->image_name = $request->file('image_name')->getClientOriginalName(); $image->image_url = $image_url; $image->save(); }
To access the uploaded image on the homepage, we need to pass the image object to the view:
<?php namespace App\Http\Controllers; use App\Upload; ... class ImageUploadController extends Controller { public function home() { // add this $images = Upload::all(); return view('home', compact('images')); } }
To display the images, we also will need to edit the home.blade.php file:
<!DOCTYPE html> <html> <head> ... </head> <body> ... <div class="row" id="displayImages"> @if($images) @foreach($images as $image) <div class="col-md-3"> <a href="" target="_blank"> <img src="" class="img-responsive" alt=""> </a> </div> @endforeach @endif </div> </div> </div> </body> </html>
So we checked if the $images object is found within the view and loop through it to display the uploaded image.
And add this to the style.css file:
#displayImages { margin: 30px 0; }
You will see the images being displayed immediately after it has been uploaded successfully to Cloudinary:
Conclusion
Cloudinary is a reliable source for storage when it comes to images in particular and any other media files in general. As shown in this tutorial, uploading images to the Cloudinary server from your Laravel web application is so simple to achieve. You can check out Cloudinary for more information on how to manipulate your images dynamically to fit any design.
Many thanks to Cloudinary for sponsoring Laravel News this week.
via Laravel News http://ift.tt/2AACDDV
0 notes