Ruby on Rails routes to controllers - ruby-on-rails

As I understand it, routes will take you from a starting point to a controller, and an action. The action brings up the associated views; so what if I don't need any views for my controller, and just want to just call a controller's underlying method, without rendering the view or route.
Lets say I have a FoodsController with several methods, and there exists methods cake, pizza, and chips within that controller. Each one queries the database for a secret message and stores it in a variable, but the request for this is going to come from some other part of our application.
To accomplish this am I supposed to use a route for this or some kind of dot syntax such as food.cake().
So I guess what I am trying to say is, hey "Server" go do this and come back to where you left off once its done.

Controller are only for URL endpoints. For example if you hit http://my.app/my_route, you need to map the my_route part to a controller action in your routes.rb file. But what happens if you type this into your browser? You'll want to see something right? So you need to return some data (json, html, erc). You can use render for this.
This is different to writing 'normal' Ruby code, i.e. Ruby outside a web framework. Do you understand what a class is and how the following works?
class MyClass
def initialize
end
def my_method
puts "my_method_called"
end
end
MyClass.new.my_method # => "my_method_called"
This is very basic Ruby and works in Rails as well, although there are some rules about where code needs to be written.
By the way, if you really want to make a controller action that renders nothing, just use:
render text: "", status: 204
return false
The status: 204 means "No Content".

You can use render json or text, if the method does not render anything, I think it should be private.

In your example you could use the cake method in another controller like so:
cake = Food.cake
Please note that this method should live in the food model and not the controller, since you do not need a view.

Related

How to create a form to trigger model method

I would like to know how to create a HTML form to send data to rails application so that specific model method guess gets triggered.
I managed to get this work in rails console, however even using HTML form guides from https://guides.rubyonrails.org/form_helpers.html I can't seem to get my head around this concept.
to generate the basic setup I used:
rails g scaffold Riddle content image_url
my model file:
models/riddle.rb
class Riddle < ApplicationRecord
def guess(guess)
content == guess
end
end
If the guess is correct(equal to content of the current object) user should see "correct guess" on the HTML page.
A form upon submit can hit a controller action. So you could do something like this:
Have a view which has the form has a form which makes a GET/POST request to an action in RiddlesController; lets call it validate_guess passing the required parameters id of the riddle and guess which is the guess that is a user input.
app/controllers/riddles_controller.rb
class RiddlesController < ApplicationController
def validate_guess
riddle = Riddle.find param[:id]
guessed_correctly = riddle.guess(params[:guess])
if guessed_correctly
render plain: "correct guess"
else
render plain: "incorrect guess"
end
end
You would also have to declare a route for this in config/routes.rb. As this works on a single Riddle object; it would be a member_action for the Riddle resource.
resources :riddles do
member do
post :validate_guess
end
end
Controller - Its the controller that renders the view and a view can only interact with the controller. Views dont directly interact with a model, and the additional controller layer does this, which provides us with a lot of structure, i.e. we can keep all data related logic in the model(though it tends to creep out of these sometimes :)). Deal with requests generation/handling at the View/Controller level and contact model to get/set info related to the business objects.
For example - your guess method is a good example. It checks whether a given value is a correct guess for a given Riddle object and returns a boolean as result(by comparing it to some attribute in the Riddle object). Going forward one could also add authentication in the controller layer, add caching or add more presentation logic. Let the model do its job of just telling the controller if the guess is correct or not for a riddle. The controller and view then deal with how to show the user that result. (e.g. Internationalize the text, style the text shown in the view or return the response in different formats like JSON/XML/HTML or maybe on a correct guess inform some other 3rd party service that the guess is correct)
Read more about the MVC pattern here and some things it enables us to achieve here

Ruby on Rails - Controller without Views

Iam new in Ruby on Rails. Normally I work with other web languages and now (of course) I try to compare it with other languages using on web.
But sometimes i have some problem to understand the philosophy and the character of Ruby on Rails. Of course i understand the concept of MVC.
But now Iam not absolutely sure:
Is ist OK to create and use a controller without views? In some cases you need a "class" for some usefull functionality used by other controllers they have views. Or is it a better style to use a module?
I try to find it out by reading a lot of articles and examples, but didnt find detailed information about this content.
When developing Ruby On Rails apps, it's recommended to put most of your business logic in the models, so for the controllers the logic need to be minimal to provide info for the views, so if it doesn't work with a view chance that you need a controller are really low.
Is it OK to create and use a controller without views
Yep it's okay.
The key thing to keep in mind is that Ruby/Rails is object orientated.
This means that every single you do with your controllers/models etc should have the "object" you're manipulating at its core.
With this in mind, it means you can have a controller without corresponding views, as sometimes, you just need to manipulate an object and return a simple response (for example with Ajax).
--
We often re-use views for different actions (does that count as not having a view):
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def search
render :index, layout: false
end
end
The notion of skinny controller, fat model is sound in principle, you have to account for the times when you may need small pieces of functionality that can only be handled by a controller:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def update
#user = User.find params[:id]
#user.update
respond_to do |format|
format.js {render nothing: true}
format.html
end
end
end
A very rudimentary example of Rails is a drive-thru:
view = input interface
controller = accepts order & delivers
model = gets order packaged etc in backend
There are times when the controller may not need a view (for example, if you update your order with specific dietry requirements), and thus the notion that every controller action has to have a view is false.
It's really about making your controller versatile enough to manage your objects correctly.
Shared controller methods can be placed in ApplicationController. Also, in Rails 4 there are concerns (app/controllers/concerns/) where you can put the modules with methods that can be used by multiple controllers.
Controller handles request and renders corresponding view template. So controller without view is absolutely nonsense.
Every time request will execute this controller, it will just end with missing template error, so you will need to create view folder and put empty files with action name inside of it, which is obviously stupid.

What's a good way to create subjective views in Rails?

I'm wondering what's the Rails Way™ to build a "subjective" view, that is, a view who's output is changed based on a provided param.
E.g., consider the following contrived case:
A user asks for a article in a blog app. In the request, she's sending the param time_zone=(-)1, to indicate that her timezone is -1. The app should then take that param, and in the output return the article and the time of the creation of that article - converted to her timezone.
The rationale for this server-side processing approach, is that it would be easy to change the client view, in particular if one's accessing the rails app through an exposed (mobile) api. (Mind you, it is no problem to handle the before-mentioned case with a client side script etc., but I'd like to avoid that.)
Somehow, I feel that this could easily belong to the model, had it not been for the fact that params isn't available there. I suppose that is for a reason. Controller is, from my point of view, definitely not the place to stick this.
The question is: should I stuff this logic in the view?
This logic would probably fit best in a subclass of your controllers. This subclass could define a filter method that sets appropriate instance variables, which you then reference in your view. I linked to a question that does exactly that for your timezone example (albeit without numeric timezone offsets, but the idea is the same). An alternate example might be say a different UI based on a URL parameter. In that case I might do something like this:
class ApplicationController
before_filter :set_ui
private
def set_ui
if params[:ui] == 'blah'
#ui = 'blah'
else
#ui = 'thing'
end
true
end
end
Then in your view you could have something like this:
<%= render :partial => #ui %>
Then any controllers that you create as subclasses of ApplicationController will have this functionality

Should I use a view to render complex json data where I need view helpers?

I'm thinking about this since a while: I'm build a single-page webapp with ExtJS library.
The whole GUI will be handled with JSON through AJAX requests, so I effectively never use the view functionality (except for the main page, where the view is six lines just to write basic tags).
However, I struck in a problem which I think will happen often during my application: I have a complex json which needs a lot of view helpers to be built, expecially for referencing other resources like images. These json objects are statically written by me, for example I need to configure ext to render some desktop-like icons which needs title and a reference to an image. I think this should be written as a view where params are an array of hashes containing title/image.
That being said, I were thinking about an approach where my json objects will be built by the view, and not by the controller as I'm currently doing.
My questions is:
Is this approach OK? I feel like violating MVC pattern when I try to use image_path helper inside my controller.
It's important to understand that I'm not trying to fetch something in the view, I'm just passing some model objects as params to views and write them in a json fashion. I can't (always) use .to_json method because sometimes I need to organize those json objects in a totally different way.
Edit 1:
I'm adding a small question that could become really useful with this approach: is possible to parse (in the controller) a YML.ERB file in the controller but allowing it (the yml) to use all those nice helpers that I have in html.erb files? I would like to use them because is nicer to build some static json objects in yml rather than plain json. If that's the case, how to do it? Remember that I'm in a controller. Thanks a lot.
You can easily write json directly in your view templates, just like you would be writing erb, or xml. E.g. if you have a controller like this
class FoosController < ApplicationController
def index
end
end
And you accept format in your routes, then you can simply create a view
<% # app/views/foos/index.json.erb %>
{ some_json_stuff: "<%= link_to 'home', root_url %>" }
This view will be rendered when you access /foos.json. This enables you to write any custom json with helpers, partials, etc.
You might want to check out Draper, which is a gem that provides view models for Rails. It is ideal for things like JSON views, which arguably have no place in the model.
It also allows you access to helpers and the request context.
class ArticleDecorator < ApplicationDecorator
decorates :article
def as_json(optsions={})
{
:id => model.id,
:foo => helpers.some_helper_method,
:secret => helpers.current_user.admin? ? "secrets!" : "no secrets"
# ...
}
end
end

Ruby on Rails controller and architecture with cells

I decided to try to use the cells plugin from rails:
http://cells.rubyforge.org/community.html
given that I'm new to Ruby and very used to thinking in terms of components. Since I'm developing the app piecemeal and then putting it together piece by piece, it makes sense to think in terms of components.
So, I've been able to get cells working properly inside a single view, which calls a partial. Now, what I would like to be able to do (however, maybe my instincts need to be redirected to be more "Rails-y"), is call a single cell controller and use the parameters to render one output vs. another.
Basically, if there were a controller like:
def index
params[:responsetype]
end
def processListResponse
end
def processSearchResponse
end
And I have two different controller methods that I want to respond to based on the params response type, where I have a single template on the front end and want the inner "component" to render differently depending on what type of request is made. That allows me to reuse the same front-end code.
I suppose I could do this with an ajax call instead and just have it rerender the component on the front end, but it would be nice to have the option to do it either way and to understand how to architect Rails a bit better in the process.
It seems like there should be a "render" option from within the cells framework to render to a certain controller or view, but it's not working like I expect and I don't know if I'm even in the ballpark.
Thanks!
How would the cell know in which controller it is rendered? This would break encapsulation.
You can use #render_cell in your controller view and maybe put some decider around it? Is that what you're asking for?

Resources