Confused on Ruby URL parameters - ruby-on-rails

I have a Questions model that has a number of different fields/parameters. If I want to view all of them, I just go to:
http://localhost:3002/questions
In order to view one specific question, I go to something like
http://localhost:3002/questions/1
How can I view the questions that satisfy a specific parameter requirement? Something like
http://localhost:3002/questions?difficulty=1
just gives the same result as viewing all questions. I know that syntactically I'm way off... but can anyone lead me in the right direction? How can I set this up on the controller-side?

You have to intercept the param in your controller and filter your results using the param.
def index
if params[:difficulty]
#questions = Question.where(difficulty: params[:difficulty])
else
#questions = Question.all
end
end

You can pass parameter depends on your condition
see the example
View:
<%= link_to "View", questions_path(:difficulty => 1) %>
note: you can send dynamic values to difficulty parameter
Controller:
def index
if params[:difficulty]
#questions = Question.all.where(:difficulty => params[:difficulty])
else
#questions = Question.all
end
end
routes.rb
resources :questions

You should provide a little more information, but maybe this will point you in the right direction if you are running a rails framework. I would create associations within the database objects so they can share certain characteristics. Check this out and see if this is what you're trying to do, http://guides.rubyonrails.org/association_basics.html . As for as the controller, that is where you'll define the method for calling the associations.

Related

How to compare two items within Ruby on Rails?

So I'm trying to re-create GitHub version control for let's say posts. I've found a way to re-create an original post using duplicate AND another method to create a new post based on the original. Cool.
My issue is being able to display both the original and the new on the same page.
What I've attempted thus far is to just rely on the show method with having:
def show
#post = Post.find(params[:id])
end
Then in the view have in the form a checkbox to allow a user to select multiple posts, click a submit, and a new page renders displaying both side by side. Preferably showing the differences between the two but that's a wish list as I deal with this first.
Actually could I just simply do?:
def other_show
#post = Post.where(params[:id])
end
I also added in status as a boolean to help on the view for marking the checkbox. Would I then need to put something in the other_show method about the status?
If you want to "recreate" some sort of version control I suggest you use something like the audited. Instead of building your own. From your example and comments it seems you don't have a clear relation between all related (versions of) posts.
Using this gem, each change to the Post content (for example, if configured properly) would be stored as an audit.
Showing the differences is a different problem. That's usually called a diff and you can find gems that do it for you, for example: diffy
To show 2 different entities on one page you need to give posts_controller both ids.
Declare your show method like this:
def show
#original = Post.find(params[:id])
#compared = Post.find(params[:compared_id])
end
Correct route to this method will look like this:
/posts/:id?compared_id=:another_id
# Example: /posts/1?compared_id=2
To construct such a link in your view, you need to declare link_to method like this:
<%= link_to '1 <> 2', post_path(#post, compared_id: '2') %>
If you want to have a page where user can check 2 checkboxes for certain posts, you'll need to construct such href via Javascript.
But in fact I wouldn't suggest you to modify show method for such a task. It is better to use show method only for showing one entity from database. You can create another method, e.g. compare and pass both parameters there.
def compare
#original = Post.find(params[:original_id])
#compared = Post.find(params[:compared_id])
end
In routes.rb
resources :posts do
get 'compare', on: :collection
end
It will give you helper compare_posts_path, which will lead to /posts/compare and you'll need to pass original_id and compared_id to it, like this:
<%= link_to 'Compare', compare_posts_path(original_id: 'some_id', compared_id: 'some_another_id') %>
It will result to
/posts/compare?original_id=some_id&compared_id=some_another_id

Ruby on Rails: What to call in view?

I have a next method in the model.
def self.next(comment, key = :id)
self.where("#{key} > ?", comment.send(key)).first
end
In my view I can say for example: (does not work)
= link_to "next", #comment.next(#comment)
What's the correct way to call this method?
routes.rb:
Rails.application.routes.draw do
resources :articles do
resources :comments do
end
end
end
You've defined next as a class method (vs an instance method), so you need:
= link_to "next", Comment.next(#comment)
If you want to be able to call #comment.next, define the instance method as:
def next(key = :id)
Comment.where("#{key} > ?", self.send(key)).first
end
It is not good style that the model knows this, you should put it in the controller. You should try a gem called kaminari, this gem lets you paginate over the elements, so in your comments controller you could have something like:
def show
#comment = Comment.order(id: :asc).page(params[:page]).per(1)
end
Then in your view, by just adding this kaminari helper:
<%= paginate #comment %>
You get the pagination bar below and everything works fine (gem's magic).
If you don't like this you could try to add that next method in the controller or find both next and current elements and link to the next element.
In my opinion the model is just a class that knows how to save and get information from the database and maybe some calculations with it's information, so all that logic related to the view should be elsewhere.

Using form_tag my instance variables are not saving when I try to search an API

I'm trying to create a simple Rails app that will retrieve API data. My original intention were not to save the search to the database, which is why I used form_tag. My search works when I run in the console, but when I call #results or #first_match, it give me nil. Many thanks in advance.
Actor Controller Method
def index
#results = API::Topic.search([:actor])
#first_match = #results.values.first
end
Actor Form
= form_tag 'actors/show', method: :get do
= text_field_tag "Actor"
= submit_tag "Show me"
Routes
RailsApp::Application.routes.draw do
resources :actors
end
Update
Since I am routing in the show method in the form. I was able to retrieve the variables in my show method in the controller. I don't know if this is the best way though.
def show
#results = API::Topic.search([:actor])
#first_match = #results.values.first
end
I think, you need to use API::Topic.search(params[:actor])

url_for knowing only model symbol and an id

Knowing these things
model_sym = :users
user_id = 1
I can do this:
url = "#{model_sym.to_s}/#{user_id}"
But is there a way I could do something like this?:
url = url_for(model_sym, user_id)
I could first "find" the user to pass into url_for, but I'd rather not.
I think you could use polymorphic_url:
polymorphic_url([model_sym, user_id])
Resources
Having written that, it seems you're getting confused about the resourceful nature of Rails.
Built on Ruby, Rails is object-orientated, which means that everything you do needs to be tied to an object (model):
The reason why this is important is because all of Rails' helpers etc are built around objects. That's why when you create a new set of routes, you can simply call resources (as resourceful is to give the object a set of attributes / methods you can call)
--
Implementation
The problem you have is you're not basing your routes around any objects - you're simply
calling symbols / numbers. Although this will work, it's not the "right" way to create Rails functionality
Your ideal situation is to build objects, and pass them to the routing structure of your application. To build an object, you'd do the following:
#user = User.find params[:id] #-> builds object
<%= link_to "Users Path", #user %> #-> pulls route from object
Something like this:
url_for(:controller => model_sym.to_s, :action => :show, :id => user_id)
You can do send("#{ model_sym.to_s.singularize }_path", id) to get the URLs you want.
This would call user_path(1) in your example.

Way to see which rails controller/model is serving the page?

This might be a slightly odd question, but I was wondering if anyone know a Rails shortcut/system variable or something which would allow me to keep track of which controller is serving a page and which model is called by that controller. Obviously I am building the app so I know, but I wanted to make a more general plugin that would able to get this data retroactively without manually going through it.
Is there any simple shortcut for this?
The controller and action are defined in params as params[:controller] and params[:action] but there is no placeholder for "the model" as a controller method may create many instances of models.
You may want to create some kind of helper method to assist if you want:
def request_controller
params[:controller]
end
def request_action
params[:action]
end
def request_model
#request_model
end
def request_model=(value)
#request_model = value
end
You would have to explicitly set the model when you load it when servicing a request:
#user = User.find(params[:id])
self.request_model = #user
There are a number of ways that I know of:
First you can do rake routes and check out the list of routes.
Second you could put <%= "#{controller_name}/#{action_name}" %> in your application.html.erb and look at the view to see what it says. if you put it at the extreme bottom you'll always get that information at the bottom of the page.
The controller can be accessed through the params hash: params[:controller]. There isn't really a way to get the model used by a controller though, because there is no necessary correlation between any controller and any model. If you have an instance of the model, you could check object.class to get the model's class name.

Resources