Rails How to Generate a Google Drive-like permalink? - ruby-on-rails

When we share a Google Drive Form, it will give our a public url.
How can we implement this in our Rails application? It should be random and not repeated.
Could anyone help me? Thanks.
Update
I mean like this url :
https://docs.google.com/forms/d/1PPVIMrDo61Er9tqYlJRntfNT73jpxtd_YJGGjXOMlAw/edit?usp=drive_web
But I want a url like this form:
http://yourhost.com/1PPVIMrDo61Er9tqYlJRntfNT73jpxtd_YJGGjXOMlAw

You should add a permalink field to the model whose show action URL you want to share. Really you could use just /model/:id but if you want to use /model/:permalink then just add the new field, generate the permalink with something like SecureRandom and save it to the model, then build the URL and share it.
You could do something like this:
class SomeModel < ActiveRecord::Base
after_create :generate_permalink
private
def generate_permalink
self.permalink = SecureRandom.urlsafe_base64(32)
end
end
Then in some view where your user can find the permalink url:
<%= link_to "Title of the model", some_model_url(some_model.permalink) %>
The above helper would create a URL that goes to the show action of your some_model controller. You could, of course, create a new action if you wanted and add it to your routes, but I'm just going the simpler way.
In your controller's show action you'd need to find the model by its permalink:
class SomeModelController < ApplicationController
def show
#some_model = SomeModel.where("id = :id OR permalink = :id", id: params[:id]).first
end
end
With a bit more tweaking in your routes and view, you can shorten the URL to what you posted in your question:
http://yourhost.com/1PPVIMrDo61Er9tqYlJRntfNT73jpxtd_YJGGjXOMlAw
For this to work, you'd have to add a route to the bottom of your routes file so that when no other route is matched, your permalink route will catch the random string and dispatch it to the controller of your choice:
# config/routes.rb
get "/:permalink", to: "some_model#show", as: :permalink
Here the param will be called params[:permalink] rather than params[:id] in your controller. You could simplify the code in your controller by making the route get "/:id" but I think it's good to be explicit.
Then, just change your view to output the correct URL:
<%= link_to "Title of the model", permalink_url(some_model.permalink) %>
Hope that helps.

Related

How to add the current id to another table in ruby-on-rails?

I am new to ruby-on-rails and have a probably pretty stupid question:
I have a ruby-on-rails-model for a book-list. On the "show"-page I have a button which should take the current id and create a new entry in another table where this id is saved as an integer.
Example:
I am on the page /titles/4 and want a new entry with the value 4 in the title_id field to be created in the table list.
How is this possible?
You should create a new controller with the create action and the associated routing.
Then you can use your route in button and pass current_id to the new controller in params.
I will use books as this second table name for this example.
First, you need to set up routes for books resource:
resources :books, only: :create
Unless you plan to add other action in BooksController its good practice to list in your routes.rb only the one you are using.
Next, you need a BooksController with create action, similar to the one you created for titles it might look somewhat like this:
class BooksController < ApplicationController
def create
# code to create a new book using provided params
end
end
Last but not least you need a button from /titles/4 site which will lead to your new BooksController via proper route:
<%= button_to "Add book", books_path(title_id: #title.id, method: :post) %>
Breaking it down:
Add book is just the name of a button displayed to the user
books_path is a path generated automatically by rails from your routes.rb file. You can look up your current routes by typing rails routes in the terminal while in the project directory.
title_id is a key under which it will be passed to our BooksController you can pick it up there to create a new book
#title.id I suppose that in current view you have access to such instance variable and can pick up its id value thanks to this call - if not pass it in show action of TitlesController
method: :post leads our routing to create action of BooksController
Hope this solves your problem!
The best solution for you will probably be to use Nested Resources. If your "other table" is reviews, it would be something like:
resources :titles do
resources :reviews
end
Your route would be:
/titles/4/reviews/new
And you could access the Title ID from the route by using params[:title_id].

How to put query params on _path rails_helper

The problem is to pass Query params throuth the helper _path .
Example I know how to pass a normal param
edit_survey_path(#poll_module)
which generates
/survey/12 because of route /survey/:id
Which is right and okay for editing
However, I want to generate the following url for new_survey_path
/survey/new?pollModule=lgpd
so how should I write the
new_survey_path(????)
At the view's controller I have the #poll_module = 'lgpd'
Then I trided
new_survey_path(#poll_module)
new_survey_path({#poll_module})
new_survey_path({pollModule: #poll_module})
new_survey_path({:pollModule => #poll_module)
new_survey_path(:pollModule, {pollModule: #poll_module})
yes some are crazy, but it were things I have found on foruns
new_survey_path(#poll_module) generates
http://rubyenv:3000/surveys/new.lgpd?
that's because the route for edit is
#routes
new_survey GET /surveys/new(.:format) so is gets on the format
I want a query param
/surveys/new?pollModule=lgpd
because on the new survey I need to search the righ questions before answering the survey, and this question depende on the module
The problem it was not the _path helper, but the componet I was using on the view
if you use the button_to, it has already a parameter for parameters
{poll_module: 'teste123'} %>
doc ref ->
https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to
or if i you use the link_to it get the query by default
doc -ref->
https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
Normally you pass a query param like this new_survey_path({key: "value1", key2: "value2"}). So the one version you have reported that you tried should have worked. Thats why i assume it could interfere with your routes. Can you try to isolate the problem and simply add the following to your project:
# routes.rb
resources :surveys, only: [:new]
# app/controllers/surveys_controller.rb
class SurveysController < ApplicationController
def new
#pollModule = params[:pollModule]
end
end
<!-- app/views/surveys/new.html.erb -->
<h1>New Survey</h1>
<p>poll module inserted as query param: <%= #pollModule %></p>
<%= link_to "testLink", new_survey_path(pollModule: "randomInput") %>
When you click on the "testLink" it should redirect you to the URL localhost:3000/surveys/new?pollModule=randomInput.
Also be sure that the route is at the top of your routes.rb file, since sometimes the ordering is what messes things up. Hope that helpes and let me know if it worked.

Routing in rails - When to route to a crud method and when to route with the given parameter

I am in need of a little help regarding routing in rails. Traditionally if I have a route in routes.rb
resources:categories
it will match www.website.com/categories/id were id is an integer. But what happens if I wanted to route to a specific user or category like so:
www.example.com/categories/apple
instead of the traditional:
www.example.com/categories/4
I currently have these two lines in my routes.rb
match 'categories/:name' => 'categories#show'
resources :categories
so www.example.com/categories/apple will route to the show method in the categories controller correctly.
but
What if I want to create a new category? Here's the problem
www.example.com/categories/new
will route to the show method, and will not route to the new method
I can place an if statement in the show method checking is params[:name] == new, but I feel that there must be a better way to solve this problem.
My end goal is to route based on the string of the category (apple) and not based on it's ID (4) but also be able to create, update, and destroy a category.
Any tips?
Thanks!
you can pass a name as a parameter, for example you can try
link_to category_path(category.name) instead of link_to category_path(category)
and it will go to categories#show in controller, the route will look like example.com/categories/categoryName, in the show action of your cateogries controller, params[:id] will have the name, you'll need something like
Category.find_by_name params[:id] instead of Category.find params[:id]
Hope this helps you.
As #pdoherty926 says in the comment, you could use FriendlyId. If you want to manage it manually, you don't have to overwrite the routes, just put the needed code in the :show action:
class CategoriesControllers < ...
...
def show
if /^\d+$/ =~ params[:id]
# ... normal workflow for integer id
elsif /soe_regexp_that_matches_names>/
# ... do your thing with names
else
raise 404
end
end
...
end
I think the most simple way to do this your way is to define a route before your
match 'categories/:name' => 'categories#show'
like this:
match 'categories/new' => 'categories#new'
match 'categories/:name' => 'categories#show'
the order matters.

Create a link to a defined method?

As my first Rails app, I'm trying to put together a simple blog application where users can vote on posts. I generated the Blogpost scaffold with a integer column (entitled "upvote") for keeping track of the vote count.
In the Blogpost model, I created a function:
def self.voteup
blogpost.upvote += 1
end
On the Blogpost index view, I'd like to create a link that does something like:
link_to "Vote up" self.voteup
But this doesn't seem to work. Is it possible to create a link to a method? If not, can you point me in the right direction to accomplish this?
What you are trying to do goes against the MVC design principles. You should do the upvoting inside a controller action. You should probably create a controller action called upvote. And pass in the post id to it. Inside the controller action you can retrive the post with the passed in ID and upvote it.
if you need serious voting in your rails app you can take a look at these gems
I assume that you need to increment upvote column in blogspots table. Redirection to a method is controllers job and we can give links to controller methods only. You can create a method in Blogposts controller like this:
def upvote_blog
blogpost = Blogpost.find(params[:id])
blogpost.upvote += 1
blogpost.save
redirect_to blogpost_path
end
In your index page,
<% #blogposts.each do |blogpost| %>
...
<%= link_to "Vote up", :action => upvote_blog, :id => blogpost.id %>
...
<% end %>
You can not map Model method to link_to in view. you can create an action in controller to access the Model method and map it using link_to, also if the action is other than CRUD, then you should define a route for the same in route.rb

Rails url needing posts/:id/the-name-of-post

I would like my rails url to look like:
/posts/345/the-great-concept
when i use the following in my posts model,
def to_param
"#{id}/#{name.parameterize.downcase}"
end
the urls look great upon mousover in the browser. and function correctly. however, once the page is loaded in the browser url it looks like:
/posts/345%2Fthe-great-concept
and to be clear, the "name" is just for good looks - the post is retrieved only by id. also i do not want to use a database slug approach.
how should i better approach this?
ps. don't want "/posts/345-the-great-concept" either ...
Its escaped because its not part of the path, but a param, so it needs to be escaped or you will be on the wrong uri.
def to_param
"#{id}-#{name.parameterize.downcase}"
end
edit: Okay, so the slash is indeed important; Here's how to tackle it:
Create a custom route for that:
# in config/routes.rb
resources :posts
match '/posts/:id/:slug' => 'posts#show', :as => :slug
Then create your slug method:
# in app/models/post.rb
def slug
title.parameterize.downcase
end
Then change your routes to the show action so the link to the fancy url:
# in any link to show; redirect after create, etc..
link_to slug_path(#post, :slug => #post.slug)
I created an app to test all this out, if interested, you can check it out at:
https://github.com/unixmonkey/Pretty-Path

Resources