I have a model that has a main_image per asset and in the attachment model this can only have one true value per asset. I am wondering if there is a way to pull this record without looping through every record to see if main_image is set to true or false.
Clarification:
I can find the value by using the following code:
<% #asset.attachments.each_with_index do |attachment, i| %>
<%= image_tag(attachment.attachment.s_640_480) if !attachment.main_image.nil? && attachment.main_image%>
<%end%>
but, I am wondering how to do this without a loop...
I don't know how to clarify any more...but something like:
<%= image_tag(#attachment.where_main_image.s_640_480) %>
I know that won't work but basically that is the concept
<%= image_tag(#asset.attachments.find_by_main_image(true).attachment.s_640_480) %>
It's not so nice to have this code in your view, so I'd recommend to put it in an instance method of your asset model:
class Asset < ActiveRecord::Base
has_many :attachments
def main_image
attachments.find_by_main_image(true).attachment.s_640_480
end
end
Then in your view you can do:
<%= image_tag(#asset.main_image) %>
You probably have to add some checks that objects are not nil. Good luck.
You can join it up like so:
class Asset < ActiveRecord::Base
has_many :attachments do
def main_image
where(:main_image => true).first
end
end
end
Use in your views like so:
<%= image_tag #asset.attachments.main_image.s640_480 %>
If i understant you need to find some entries in database if the value of it is true or false right ?
So you need to make a method inside your model or use a find with condition in the controller, you can find all what you want inside the documentation.
Related
is a little project and I try to associate patient model with consultations. one patient has_many :consultations, in my form I have:
<%= f.association :patient %>
I pass the id parameter from the patient to the action 'new' in this way:
<%= link_to new_consultum_path(:id => #patient.id) %>
And in the view I have:
How can I make that the f.association field take the correspondent patient_id automatically?
How can I be sure that the patient_id is the current patient?
If I want to hide this field is that ok if I put
instead of
Is a better way to do this?
And why in the view shows me # patient:0x007f4e7c32cbd0 ?
thanks for your help.
And why in the view shows me # patient:0x007f4e7c32cbd0
This is a Patient object.
It means you need to call an attribute of this object - EG #patient.name.
--
f.association field take the correspondent patient_id automatically
This might help:
It looks like Organization model doesn't have any of these fields: [
:to_label, :name, :title, :to_s ] so SimpleForm can't detect a default
label and value methods for collection. I think you should pass it
manually.
#app/models/patient.rb
class Patient < ActiveRecord::Base
def to_label
"#{name}"
end
end
Apparently, you need to have either title, name or to_label methods in your model in order for f.association to populate the data.
-
How can I be sure that the patient_id is the current patient?
If you're having to verify this, it suggests inconsistencies with your code's structure. If you need the patient_id to be set as the current patient, surely you could set it in the controller:
#app/controllers/consultations_controller.rb
class ConultationsController < ApplicationController
def create
#consultation = Constultation.new
#consultation.patient = current_patient
#consultation.save
end
end
I can provide more context if required.
You want to associate consultations to patients using fields_for, which is similar to form_for, but does not build the form tags.
It you start with your patient object, you can iterate through the consultation associations binding it to form fields as you go.
it would look something like this
<%= form_for #patient do |patient_form| %>
<% patient_form.text_field :any_attribute_on_patient %>
<% #patient.consultations.each do |consultation| %>
<%= patient_form.fields_for consultation do |consultation_fields| %>
<% consultation_fields.text_field :any_attribute_on_consulatation %>
<% end %>
<% end %>
<% end %>
Sorry, the code may not be exactly right.
Check out the docs for field_for here
You will also have to set accepts_nested_attributes_for consultations on patient. When you set accepts_nested_forms_for, Rails will automatically update the associated consultations object to the patient and save any edits you have made. You DEFINITELY want to use accepts_nested_attributes_for most nested form handling of this type.
my guides can have many guide_pics. In my show guide view, I want to show the pics. I'm trying to use
<%= image_tag #guide.guide_pics if #guide.guide_pics %>
Instead of the image, the page renders with the text:
So it seems like something is there, I just have to get the picture.
But in the debugger this gives
#<ActiveRecord::Associations::CollectionProxy []>
Does that mean an empty object is returned? If that is the case, maybe I seeded the db wrong:
g1.guide_pics.build(picture: File.open(File.join(Rails.root, '/public/2015-08-28 18.55.47.jpg')))
Otherwise, maybe I set up the association wrong.
My guide_pic model
class GuidePic < ActiveRecord::Base
belongs_to :guide
validates :guide_id, presence: true
validates :picture, presence: true
default_scope -> { order(created_at: :desc) }
end
My guide model
class Guide < ActiveRecord::Base
belongs_to :user
has_many :guide_pics, dependent: :destroy
#mount_uploader :picture, PictureUploader
end
guide_pics is an association, and will return one or more guide_pics.
So you will have to iterate over all guide_pics, as follows:
<% #guide.guide_pics.each do |guide_pic| %>
<%= image_tag guide_pic.picture.url %>
<% end %>
Notice I write guide_pic.picture.url: I am assuming you are using a gem for your attachments, like carrierwave or something similar, which can build a url for your image --if not, you will do add that yourself.
But if you just want to show the first picture, you could do something like
<%= image_tag #guide.guide_pics.first.picture.url if #guide.guide_pics.count > 0 %>
Rails is doing correctly, you are misunderstanding.
while a model is having many pictures (has_many relation) rails is auto-generating a method to access those.
In this case Guide.guide_pics is making a query to the DB, something like
SELECT * from guide_pics where guide_id=5
as you can see - this is selecting all rows, the hole set of data which is associated with one guide. This is what ActiveRecord is called an ActiveRecord::Collection.
First of all, yes, you seeded the DB wrong!. The .build method is not saving anything to the database, you should call the .create method.
If you are having any objects in your database you have 2 (3) ways of rendering the image.
<%= image_tag #guide.guide_pics.first.url if #guide.guide_pics.any? %>
This will take the first picture from the Collection if any is in there.
This is bad code.
another option would be to say .take instead of .first.
better code would be something like
<%= image_tag #guide.preview_picture %>
to do so you need a model function
class Guide
def preview_picture
guide_pics.first.url || "/images/no-logo.jpg"
end
end
this will automatically takes the first picture or returns the string of a default one.
my advise to you: have a look on Carrierwave, Dragonfyl or Paperclip. Thise are awesome FileUploading Gems - fitting your needs.
Look at the documentation of image_tag it expects source of image not collection_proxy You need to iterate the list and show images one by one
<% #guide.guide_pics.each do |pic|%>
<%= image_tag pic %>
<% end %>
Note: pic can be url or name of pic depending on your pics saving technique.
I'm adding a new model to my equasion and I'm wondering if there is a way to associate two models into one model then display any/all results within a view. For example, here is what I've currently have;
#tweet_category.order("position").each do |tweet|
<%= tweet.title %>
end
just a short example... now what if I added facebook into this. I was first thinking of creating a model thats named stuff then associate it to tweet_category and facebook_category like so;
class Stuff < ActiveRecord::Base
attr_accessible :title
belongs_to :user
has_many :tweet_category
has_many :facebook_category
end
Now in my controller I'm guessing I would do the following;
class StuffController < ApplicationController
def index
#stuff_list = Stuff.find(:all)
end
end
and in my view I would just simply do the following from above view;
#stuff_list.order("position").each do |stuff|
<%= stuff.title %>
end
am I understanding the logic here??? would that work having two models / two tables db.. etc..
First of all, I don't understand why you would need that "stuff" model. It belongs to users and has_many tweet_category and facebook_category, and just does nothing but offering a "title", when your User model could do the job ( I mean, each user could have many tweets and fb category, instead of having one or several "stuff" which has/have many of them ).
Anyway, if you want to make links between your models and then display everything in a view, first in your User model you just have to do :
class User < ActiveRecord::Base
...
has_many :facebook_categories #( I don't know how rails would pluralize it, btw, I'm just making an assumption )
has_many :tweeter_categories
end
and
class Facebook_category
...
belongs_to :user
end
and do the same fot the tweeter category
Then in your controller :
def show_everything #Here it's a custom action, but you can call it wherever you want
#users = User.all
end
And finally in your view :
<% #users.each do |user| %>
<% user.facebook_categories.all.each do |fb_c| %>
<%= fb_c.title %>
<% end %>
<% user.tweeter_categories.all.each do |t_c| %>
<%= t_c.title %>
<% end %>
<% end %>
Maybe just try to grab a better name for your models, so the pluralization doesn't get messy ( and I saw that the ".all" method is deprecated, so maybe replace it with something
Hope it helps !
Edit :
Basically, when you're doing
#users = User.all
What rails' doing is putting every hash defining every "User" in an array. So, if you want to mix two tables' arrays inside a single array, you can do something like this :
#categories = [] << Facebook_category.all, Tweeter_category.all
You will then have an array ( #category ), filled with 2 arrays ( one ActiveRecord relation for Facebook_category and one for Tweeter_category ). Themselves filled with hashes of their model. So, what you need to do is :
#categories.flatten!
Here's the API for what flatten does ( basically removing all your nested arrays inside your first tarray )
Now, you got a single array of hashes, being the informations from both your model's instances. And, if these informations can be ordered, in your view, you just have to :
<% #categories.order("updated_at").each do |i| %>
<%= i.title %>
<% end %>
Note that User has many Photos. I'm using the friendly_id gem to generate a slug for photos. This is my Photo model:
class Photo < ActiveRecord::Base
extend FriendlyId
friendly_id :photo_by_author, :use => :slugged
def should_generate_new_friendly_id?
title_changed?
end
def photo_by_author
"#{title} by #{user_id}"
end
belongs_to :user
end
My path is profilename/photos/title, this is my routes.rb
scope ':profile_name' do
resources :photos
end
In my controller, I'm doing #photo = Photo.all.
I'm trying this but isn't working: <a href="<%= photo %>">
How can I do the photos#show path??
Have you try
<% #photo.each do |photo| %>
<%= link_to photo.photo_by_author, photo %>
<% end %>
or
<a href=<%= photo %>" ><%= Photo.first.photo_by_author %></a
>
inside the block
or in your console rails c -s
include Rails.application.routes.url_helpers
default_url_options[:host] = "localhost"
photo_url(Photo.first)
Link_To
Firstly, you shouldn't be trying to populate a "naked" <a> with your ruby variable - you need to use the <%= link_to %> helper:
<%= link_to photo.title, photo_path(photo) %>
The problem is your scope, especially considering this scope is used to determine a variable. I believe the issue is that since Rails expects a variable from this scope, it will not be able to process any of the links without having it
The simple way to resolve that error, as mentioned in the comments,is to populate the route with both values:
<%= link_to photo.title, photo_path(profile_name, photo) %> #-> photo & profile_name need to be declared
You'll want to look up a rake routes to make this work
Friendly_ID
If you want to populate the friendly_id slug values for this route, you'll need to do two things:
Pass the profile_name value as a "slug" (not ID)
Pass the photo object itself
I noticed in the comments, Tiago Farias posted a possible solution for you. If you want that to work with friendly_id, you'll need to pass the photo object without defining the id attribute (this will let friendly_id work its magic)
The next thing you need to consider is that since :profile_name is not tied to any "resource" (controller / model), friendly_id won't be able to populate the name / value that you'd expect. In this case, you need to set the value yourself (by defining it explicitly in your controller)
I'm trying to get the text "Tags:" to show up only if tags are present, so I did the following in my view:
<% if #tags.present? %>
<%= puts "Tags:"%>
<% end %>
Which doesn't work... I'm a beginner, and have no idea what I'm doing wrong.
Thanks
EDIT:
A tag belongs to an Article.
Tags is defined in my Article model as:
def tag_tokens
self.tags.collect{|t| t.name}.join(", ")
end
def tag_tokens=(tags_delimited)
tags_delimited.split(",").each do |string|
self.article_tags.build(:tag => Tag.find_or_create_by_name(string.strip.downcase))
end
end
I'm trying to make it so that when an article has tags the word "Tags:" shows up before the list of tags, and when an article doesn't have any tags, the word "Tags:" doesn't show up.
Right now <% if #tags.nil %> just causes "Tags:" to show up on every post.
You don't use puts in views -- puts causes the text to go to your console. This will fix it:
<% if #tags.present? %>
<%= "Tags:"%>
<% end %>
You also don't need to use .present? by the sound of it. If you only want to see if it's been set, you should use .nil? instead. You can also condense this down to a single line.
<%= "Tags:" unless #tags.nil? %>
UPDATE: It looks like the tag_tokens method is broken for you in both the getter and setter. Your setter isn't actually saving anything by the looks of it (.build returns a new object, you need to save it). Your getter is also referencing tags, instead of article_tags which is what you're trying to save by the looks of it. Changing it to this should work for saving:
self.article_tags.build(:tag => Tag.find_or_create_by_name(string.strip.downcase)).save
This is assuming that you have a line that is something like:
has_many :article_tags
has_many :tags, through: :article_tags
Which I'm assuming you do based on your setter.
I assume this is a many-to-many relationship, but it looks like you're using has_many :through, rather than has_and_belongs_to_many. Is there a reason for this? If you're using has_and_belongs_to_many you should be able to do this:
has_and_belongs_to_many :tags
def tag_tokens=(tags_delimited)
self.tags = []
tags_delimited.split(",").each do |string|
self.tags << Tag.find_or_create_by_name(name: string)
end
end
If you do that, you should not have an ArticleTags model at all, and you should have a table called articles_tags with no primary column, and an article_id and tag_id column.
Update 2:
You're not setting #tags to anything, which is why it's always nil. #tags is a variable, which needs to be set to have a value just like #articles is being set in your controller's index method. Regardless, since this is for an index method, you wouldn't want it to be a single instance variable regardless. You should be accessing your tag_tokens method for that particular instance. app/views/articles/index.html.erb lines 53-55 should be changed to this:
<%= "Tags:" if article.tags.any? %>
Check the answer by sgrif, it contains a lot of good points. To just answer your main question:
In erb (the "language" used for view templates in Rails) you can use <%= ... %> to interpolate the result of some Ruby code into your view template.
When you are doing:
<%= puts "Tags:" %>
the following happens:
Ruby evaluates/executes your code: "Tags: " is printed to STDOUT and nil is returned since a call to puts alsways returns nil
erb interpolates the result into your template, the result is nil, which shows up as "nothing"
To fix it, just use:
<% if #tags.present? %>
<%= "Tags:"%>
<% end %>
or, since you are not doing anything in Ruby, you can just use:
<% if #tags.present? %>
Tags:
<% end %>
What has #tags been defined as? Where do you want to check if it is present?
Do you want if #tags.nil?