multiple views in a rails page - ruby-on-rails

I have a very high level question that I cant find an answer to that makes sense to me. I understand it''s a terribly broad question but I'm only after some pointers in where to look for answers, not instructions on how to build my site.
So... If I want to render two different types of content in a single page using rails, how would I go about doing this? And how would I format the url? Say I create a gallery model and controller which has information about the gallery and perhaps a description, then I create a gallery-entry controller and model that belongs to the gallery which has an image and image name. If I want to create a url something like www.siteURL/galleryName/GalleryEntry that renders both the gallery info and description and all the associated gallery-entries but also a larger version of the gallery-entry that is named in the url where would i start and how would i structure this? How would i go about creating a url that has multiple attributes and how would i access them in the controller/view?
Thanks - and sorry for the vague question

There's several ways to go about it.
Your URL looks like a "vanity" URL that would exist in addition a normal RESTful route (galleries/:gallery_id/entries/:entry_id). The difference is that you don't want to show just the gallery entry.
If you want to specifically differentiate between different views of the same resource there are a number of ways it could be done, the two I'd consider first are adding another action, or adding a disambiguating query parameter. In this case, it's a hybrid, so I'd probably create a custom match and controller method.
The mapping might look like:
match ':galleryName/:entryName' => 'gallery#highlight_entry' # Or whatever
The action would be (more or less):
def highlight_entry
#gallery = Gallery.find_by_name(...)
#entries = #gallery.entries
#highlighted_entry = # pull from #entries, or retrieve
# Also, filter entries/etc. so the highlighted one doesn't show up
# etc
end

Related

Copy a dynamic page in a view

My knowledge of Rails is pretty basic, but I have to fix a problem in a Rails project and the programmer can not be reached. So I'm trying to fix it myself, but I'm stuck.
The project revolves around user being able to add pictures to competitions, and to be able to vote on those pictures. The plan was to have to voting on the same page as the images, but this gives a few bugs in the JS and slow performance. So I want to have the voting and the overview on two different pages.
The problem is that I can't figure out how to create another page inside the views > competitions folder and link it up with the rest of the project. The easiest solution for me would be to copy the show.html.haml and paste it like votepage.html.haml but obviously that isn't so easy.
in the view > competitions folder there's an index.html.haml file, this displays a list of current competitions and gives a admin the ability to remove, add or edit certain competitions. When a user clicks on a link to a competition this gets rendered in the show.html.haml. On this page all the images that have been uploaded in that competition are shown. On that page I want a link that refers to the voting section. When a user clicks that link it should go to the votepage.html.haml (which is 100% the same as the show.html.haml but with different styling and added javascript). For now there's no need to actually make the voting work, "faking" it through front-end is good enough.
TLDR: I want to copy/paste a page in a view, but I don't know how to hook it up to the project.
Update1. I've used the console command rails generate controller competitions votepage which created a votepage for me. I could visit this one as well on http://localhost:3000/competitions/votepage
With the following code
- #competitions.each do |competition|
#container.js-masonry
.painting.item
= link_to competition do
- competition.pictures.shuffle.each do |picture|
= image_tag(picture.image_url)
I can insert images from the competitions in the page. But the problem is that I gets images from all competitions. And not so much competitions/1 , competitions/2 etc.
What you're missing is updating the routes file so that Rails knows what you want
Views:
competitions/
show.html.haml
vote.html.haml
...
Routes:
resources :competitions do
get :vote, on: :member
end
Member makes it behave like the show action, requiring a format like competitions/:id/vote
Edit:
You want to do the routes like above, but in the controller, make sure you get the competition from the id that will get passed
Controller:
def vote
#competition = Competition.find(params[:id])
end
And then instead of looping through all the competitions, you can just take the loop out and reference #competition
The basic answer is that you also need to copy the show method from app/controllers/competitions and make a votepage method with the contents in the same file.
This guide will help explain how views get wired (by the controller) to models: http://guides.rubyonrails.org/action_controller_overview.html

Where to store editable content?

I am building a Rails app that is intended to be eventually used by non-technical people. It consists of a few pages with blocks of text and a special page with interactive canvas drawings.
I want to allow them to easily edit any piece of text contained in the application. What are the best ways to achieve that? Currently, text is written in the different views of the application, which does not allow them to edit it without having to connect via FTP or similar and search for the right file.
I am thinking of three solutions:
Store all blocks of text in the database. On each page, fetch the requires blocks and insert them before rendering. Build a page that lists all blocks in the database in editable areas with a save button.
Store all blocks of text in a json file. Create a model that can read the file and fetch the blocks required by the views. Build a page that lets you edit each block and save it in the file.
Create some kind of password-protected admin interface that fetches all file in the views directory, use regexp to find blocks of text and allow the users to edit each block and save.
From my point of view, all of my three solutions look pretty bad. It does not feel okay to do so many calls to the database? Store your entire website text in a file? Parse HTML with regexps?
What are the usual approaches used to solve this problem?
There's a great book out there: Crafting Rails 4 Applications. Here's the link to source code from the book. You will find example in templater folder. Basically, you will be able to create custom templates based on the request parameters (just like Rails does).
Update. Here's a couple of links:
Default views in Rails 3.0 with custom resolvers by José Valim (author of the book, by the way).
Implementing a Rails 3 View Resolver.
Also, here's 5 coins from me. Basically, it works like this. You need to define your own resolver and connect it to your ApplicationController (or any other controller you want):
class Resolver < ActionView::Resolver
# some code here
end
class ApplicationController < ActionController::Base
append_view_path Resolver.new
end
During the rendering process, Rails will ask your controller's resolvers to provide a template (it will go through each of them, until it finds template or until there won't be any resolvers left). In order to provide template, your resolver needs a find_templates method:
def def find_templates(name, prefix, partial, details)
# some processing here
end
So, based on this method parameters, you're going to provide some database records. But even if you have some kind of model already, Rails expects this method to return ActionView::Template instance. It can be initialized like this:
ActionView::Template.new(source, identifier, handler, details)
So, that's how your find_templates should look like:
def find_templates(name, prefix, partial, details)
template = DatabaseTemplate.find... # your custom model for DB templates
ActionView::Template.new... # initializing actual template
end
Both model and resolver in detail are presented in the book's source code (templater/3_final/app/models/sql_template.rb).
I have done that a couple times with awesome user satisfaction by using this:
http://jejacks0n.github.io/mercury/
There is also a Railscast available which gives you a good overview and step by step instructions:
http://railscasts.com/episodes/296-mercury-editor
Hope it helps. It looks good and is easy to use for end users.

Changing urls in ruby on rails depending on different conditions

I'm new to ruby on rails....I wanted to know if there is a way to change the URL displayed depending on the client's response. I mean... here's an example:
I'm making a project showing listings in various places...
Now in general I have a home page, a search page, and a detail page for listings. So, respective URLs are officespace/home, officespace/search?conditions, officespace/detailpage?id=(controller-officespace)[&Conditions eg.---price,size,place,type...]
So, every time the client makes a request for search, the same URL is shown, of course with the given conditions.
Now I want that if the client asks for only the place and mentions nothing about size, price, etc., the url should be /listing/location_name.
If he mentions other conditions, then it'll be listing/(office_type)/size(x sq feet)_office_for_rent_in_locationname)
B.t.w. (I already have a controller named listings and its purpose is something else.)
And so on ........... Actually, I want to change URLs for a number of things. Anyway, please help me. And please don't refer me to the manuals. I've already read them and they didn't give any direct help.
This is an interesting routing challenge. Essentially, your goal is to create a special expression that will match the kinds of URL's you want to display in the user's browser. These expressions will be used in match formulas in config/routes.rb. Then, you'll need to make sure the form actions and links on relevant search pages link to those specialized URL's and NOT the default pages. Here's an example to get started:
routes.rb
match "/listing/:officeType/size/:squarefeet/office_for/:saleOrRent/in/:locationName" => "searches#index"
match "/listing/*locationName" => "searches#index"
resources :searches
Since you explicitly mentioned that your listings controller is for something else, I just named our new controller searches. Inside the code for the index method for this controller, you have to decide how you want to collect the relevant data to pass along to your view. Everything marked with a : in the match expressions above will be passed to the controller in the params hash as if it were an HTTP GET query string parameter. Thus we can do the following:
searches_controller.rb
def index
if params[:squarefeet] && params[:officeType] && params[:locationName]
#listings = Listing.where("squarefeet >= ?", params[:squarefeet].to_i).
where(:officeType => params[:officeType],
:locationName => params[:locationName])
elsif params[:locationName]
#listings = Listing.where(:locationName => params[:locationName])
else
#listings = Listing.all
end
end
And to send the user to one of those links:
views/searches/index.html.erb
<%= link_to "Click here for a great office!", "/listing/corporate/size/3200/office_for/rent/in/Dallas" %>
The above example would only work if your Listing model is set up exactly the same way as my arbitrary guess, but hopefully you can work from there to figure out what your code needs to look like. Note that I wasn't able to get the underscores in there. The routes only match segments separated by slashes as far as I can tell. Keep working on it and you may find a way past that.

Search action in ReSTful rails model

So, I'm quite new to Rails and still working my way through the principles. I suppose like most people, I have started creating that basic CRUD. Okay. Done.
Now I want a new action: search. As it turns out, it is not one of the 7 rest sacred (!) actions (if got it right). While I know I could implement new custom actions and resource it and everything, I read in a few places to try my best to stick to the standard ones as long as possible. Okay. What would be the correct way?
Again a few sources like this guy suggest thinking of my scenarios in therms of nouns, case in which seems I'd need a "search" controller...? It just doesn't convince me that I'd have to create a whole class whereas I'd normally do def search just to keep it ResTful.
What did I get wrong? What would be the common solution here?
thanks.
REST is a concept, not a religion :-). But the core verbs are GET/POST/PUT/DELETE which map to their associated HTTP verbs. What's in the URL is typically a reflection of this, and (this is more the Rails philosophy) following convention can make everything much easier. The URLs you get with generic rails (e.g. scaffold) are not particularly ideal in several ways, but they work, and you can change them.
So, yeah, for search (assuming it's starting simple, e.g. finding records in a single model, say Product) then you could do a GET with a query string like this
def search
#results = Product.where("name ILIKE ?", params[:query])
...
end
Which would result in a URL like /product/search?query="foo" -- nothin' wrong with that.
It depends if your search is against ONE resource or many resources. For example if you have a ProductsController and you want to implement a search feature only for your products, you could create a collection action called "search" (the url would be /products/search)
If your search is for many resources, I'd create a SearchesController with a singleton resource :search in my routes file.
Then again, when you implement search functionality in your application, don't put all the logic in your controller but create models classes to handle your search. You can even create an abstract class to map to your search form and thus avoid using '*_tag' fields to create your search form.
See : https://github.com/slainer68/basic_active_model
If you want to adhere to REST (which is a guideline really, it has pros and cons), then the slideshare you link to is recommending the right way to do things.
So, for example if you have a comments_controller, and you want to be able to search comments, you could create a comments_search_controller. The search form would be at comments_search_controller#new, which would POST to comments_search_controller#create.
Yes, you are creating another class doing it this way, but that's not much different than creating another action in the comments_controller, and it does keep things consistent and separated. You wouldn't need a new CommentSearch model or anything, just that controller, which asks your Comment model for the relevant search results.

Basic Rails 3 Routing Question

I am trying to make some clean URLs in a Rails3 application I am working on... but I am having a hard time understanding how to (or if I even should) customise my routes to make this work.
Here is the example:
I have a list of Stores. Each store is in a category (health, sports etc). Each store has a location.
I have 2 ways I'd like to present the data. One display is a list of all the stores in a directory type structure, the other is on a map.
Ideally I'd like my URLs to work something like this:
/stores/health/map (or /stores/map/health) to show just the health stores on a map (where essentially the map parameter is effecting which view is displayed, but still using the Index controller... which using a collection in my route doesn't seem to suit)
The other URL I'd like is /stores/sports/ to show just the sports stores in a directory view (the default) for example...
I am not entirely clear how I can manipulate the routes to handle this...
Here is my current Route which isn't really doing it for me:
resources :stores do
collection do
get 'map'
end
end
On top of that, I'd like to be able to add filters without using ?query=params... so:
/stores/sports/hockey , would essentially filter out only hockey stores...
I have no issues doing this with ?query, it's just putting my params into a nicer URL that I'm trying to achieve.
The documentation does not seem to outline what I am trying to do, so Im assuming what Im trying to do is wrong.
Is this breaking REST? Am I looking at it all backwards?
Thanks for your help, JD
You might be overthinking this. :-)
If you want to route HTTP Get of 'stores/health/map' to the StoresController with an action name of, say, health_map, what you need to do is:
get 'stores/health/map' => 'stores#health_map'
Anything that is a clean URL and doesn't modify data and uses HTTP GET is RESTful. (And that is coming from a co-author of a book on REST). It is when you wish to modify data that you need to be more careful on how you use methods.
To do filtering, try something like:
get '/stores/sports/:filter' => 'stores#sports'
The value of the filter will come into your method as params[:filter]

Resources