generic path for arbitrary model - ruby-on-rails-3

In my step-definition, I want to create a path to a named route for an arbitrary Model, like so:
Given(/^a new "(.*?)" form$/) do |model|
path = send("new_admin_#{model.downcase}_path".to_sym)
visit path
end
Used as
Given a new "Image" form
Given a new "User" form
I recall using a helper method in the past for this, one that allowed me to pass a modelname and some additional options, like the action and object or IDs. But I cannot find that anymore. This is for Rails 3.2.x.
Is there such a "magic" helper? If so, what is it? If not, are there common patterns to create paths to arbitrary Models?

Related

Dot.NET Core Routing and Controller Processing discrepancy

I am trying to use the asp-route- to build a query string that I am using to query the database.
I am confused on how the asp-route- works because I do not know how to specifically use the route that I created in my cshtml page. For example:
If I use the old school href parameter approach, I can then, inside my controller, use the specified Query to get the parameter and query my database, like this:
If I use this href:
#ulsin.custName
then, in the controller, I can use this:
HttpContext.Request.Query["ID"]
The above approach works and I am able to work with the parameter. However, if I use the htmlHelper approach, such as:
<a asp-controller="Report" asp-action="Client" asp-route-id="#ulsin.ID">#ulsin.custName</a>
How do I get that ID from the Controller? The href approach does not seem to work in this case.
According to the Anchor Tag Helper documentation, if the requested route parameter (id in your case) is not found in the route, it is added as a query parameter. Therefore, the following final link will be generated: /Report/Client?id=something. Notice that the query parameter is lowercase.
When you now try to access it in the controller as HttpContext.Request.Query["ID"], since HttpContext.Request.Query is a collection, indexing it would be case-sensitive, and so "ID" will not get you the query parameter "id". Instead of trying to resolve this manually, you can use a feature of the framework known as model binding, which will allow you to automatically and case-insensitively get the value of a query parameter.
Here is an example controller action that uses model binding to get the value of the query parameter id:
// When you add the id parameter, the framework's model binding feature will automatically populate it with the value of the query parameter 'id'.
// You can then use this parameter inside the method.
public IActionResult Client(int id)

What's a good way to insert a resource id into the params of another resource?

I'm really new to programming, so I'm having trouble explaining this -- please forgive.
I have a Document model and a Note model in my rails app. A note belongs to a document, and a document has many notes -- the foreign key in the notes table is document_id.
On my document show page, I have a form for a note which uses a :content attribute as a text_area field.
What I'd like to do is pass the document's id into the note params so the note would have both the :content the user submits alng with the :document_id based on the document_path.
Currently I'm adding the :document_id into the note's params hash using a hidden_field form helper, and sending the whole thing to the NotesController, but I hope there's a cleaner / perhaps easier way.
If this makes sense, can someone suggest a better way to do this? Thank you.
In your routes have something like
resources :documents do
resources :notes
end
Then you should be adding a note via this route
/documents/5/notes/new
Then in your NotesController have
def create
#document = Document.find(params[:document_id])
#note = #document.notes.build(params[:note])
if #note.save
# Blah
else
# Blah
end
end
(In no way has this been tested - but it gives you an idea of how to do it in a RESTFUL style without hidden fields)

Multiple Resource Routing In Rails

I have two unrelated models, say Person and Building. When the app receives a url like www.mysite.com/JohnDoe/EmpireState I would like to show properties of the Person with the name johnDoe, and the same for the building with the name EmpireState.
I'm confused as to the routing part specifically. I'm unsure if I need to create a pages controller that can return the objects from the database. How should I go about doing this?
Am hoping for something like below?
match ':user_name/:building_name', :controller => pages
If those two are not related, you shouldn't do it that way. If they ARE related, we call that nested resources.
Example:
resources :projecs do
resources :tasks
end
Sample URL: "/projects/12/tasks/1281"
Edit:
If they are NOT related (taken from my comment):
In your BuildingsController you can fetch the parent informations too. If you use the match route in your question, you'll have params[:user_name] AND params[:building_name] available and can fetch anything you want with them...
Building.find_by_name(params[:building_name]) # return all Buildings based on URL param

Ruby on Rails 3: rails_admin + puret?

Did someone try to integrate puret into rails_admin? I can't make a language switch to edit different translations :(
Changing I18n.locale forces whole rails_admin to use specified locale.
Now I got the solution. The two can work together well. In short:
Delete the pureted column(s) in your model
If you have the column pureted still in your model, rails form helper will bypass puret. That is, if a model called Post has a field called contents to be i18ned, the table posts SHOULD NOT have the column contents.
Actually we should use globalize3 instead. With this you do not need to remove the original column. And puret doens't support nested attributes assignment. globalize3 works very well.

How can I store extra data with a validation error message in Rails 3?

I'm trying to store some additional data along with the standard error message in a custom validator in Rails 3.
For example, (ignoring built-in validators) suppose I wanted to check to see if a post is a duplicate before it's saved. I might write my custom validation method like this:
class Post < ActiveRecord::Base
# prevent duplicate posts
validate do |post|
duplicates = Post.find_all_by_body(body)
errors.add_to_base("Post is a duplicate!") if duplicates.length
# something like this is desired:
# errors.add_to_base("Post is a duplicate",
# :extra => { :duplicates => duplicates })
end
end
This will let the user know there are duplicates, but along with adding the error message I would also like to store the duplicates so they can be displayed to the user. How would I store the list of duplicate posts retrieved during validation such that it is associated with the record's errors for the body field, and available to my view?
A simpler example might be length validation: If a field exceeds its maximum length, how can I store the maximum length along with an error message without simply interpolating it into the message as Rails currently does?
I have not had to do this before, but my first thought is to create a new method on the object called duplicates.
attr_accessor :duplicates
Then in your custom validate method, you can set the duplicates on the object making them available to the view when you render the errors. Notice your current code doesn't change much:
validate do |post|
duplicates = Post.find_all_by_body(body)
errors.add_to_base("Post is a duplicate!") if duplicates.size > 0
end
You would then have to intercept that error in the view manually so that you can print out all the duplicates if the "Post is a duplicate!" error is encountered.
You can pass options to the error but they are only used as substitution in i18n templates. To make a long story short, no you can't store meta-data about your error in the errors hash. If you need such a functionality you'll need to look into the ActiveModel::Errors module in Rails core.
Update:
Another solution could be that instead of pushing a string into error hash, you stuff an instance of your own class, a class which quacks like a string but would be decorated with extra methods and state and such like.